2014/5/04

1 はじめに

libGDX は、Javaでゲームを作るためのライブラリです。 マルチプラットフォーム対応で、PC(Windows,Linux,Mac), Android, iOS, HTMLに対応しています。

libGDXは、日本での知名度はイマイチのようですが、海外ではかなり人気があるようです。 実際、ググってみると、英語のドキュメントは沢山みかけますが、日本語のドキュメントはまだまだ少数です。

また、公式ドキュメントも大変充実しています(英語のみ)。

実のところこのドキュメントを読めば大抵の事は解決します。

ただ、私もそうなんですが、日本語情報がないってだけで、 重い腰が上がらないって人も多いと思います。 そんな人向けに(というより自分の勉強ついでに)、 そして少しでもlibGDXを使用する人が増えることを願い、 少しずつ記事を書いていこうと思います。

この記事が、libGDXを学ぶためのきっかけになって頂ければ幸いです。

その2は こちら

このシリーズの目次は こちら

2 プロジェクトを作る

libGDXでは、専用のプロジェクト生成アプリが用意されています。 マルチプラットフォームの性質上、プロジェクトの構成が複雑なので 素直にこのアプリを使用したほうが良いかと思います。

起動は、以下のような感じです。Windowsならばダブルクリックで起動できるでしょう。

$ java -jar gdx-setup.jar 
Usage: GdxSetup --dir <dir-name> --name <app-name> --package <package> --mainClass <mainClass> --sdkLocation <SDKLocation>
dir ... the directory to write the project files to
name ... the name of the application
package ... the Java package name of the application
mainClass ... the name of your main ApplicationListener
sdkLocation ... the location of your android SDK. Uses ANDROID_HOME if not specified

setup.png

Figure 1: 起動したところ

入力値は見たままですが、

Name プロジェクトの名前(設定ファイルでアプリ名として利用される)
Package プロジェクトのパッケージ
Game class 起点となるクラス
Destination プロジェクトの出力ディレクトリ(ディレクトリは存在しなくても自動作成してくれる)
Android SDK AndroidSDKへのパス

となります。

Generateボタンをクリックすれば、プロジェクトが生成されます。 必要なライブラリ(gradle、dllやsoなど)も全部まるっとダウンロードしてくれるので楽チンです。

以降、プロジェクトを ~/dev/libgdxtest/ に生成した前提で話をすすめます。

2.1 注意点

今後プロジェクトを実行する際、挙動がおかしいなと思ったら、 下記のデイレクトリを(バックアップしたうえで)削除して再実行してみてください。

$ rm -rf ~/.m2
$ rm -rf ~/.gradle

ともにjarファイルなどの依存ファイルを保存するディレクトリですが、 稀に状態がおかしくなるようです。

3 IntelliJで使う

Eclipseに比べて軽いと評判の IntelliJ IDEA での扱い方です。

3.1 プロジェクトのインポート

まずは、IntelliJを起動し、Import Projectを選択します。 既に別のプロジェクトを起動していた場合は、「close Project」を選択します。

IntelliJIDEA_007.png

Figure 2: IntelliJの最初のダイアログ

gdx-setup.jar で生成したディレクトリを選択します。

SelectDirImport_004.png

Figure 3: プロジェクトディレクトリを選択

Gradleを選択し、「next」ボタンを押下します。

ImportProject_006.png

Figure 4: Gradle選択

「Use default gradle wrapper」を選択します。

ImportProject_008.png

Figure 5: defaultを選択

最後にFinishボタンを押下します。最初のインポートには時間がかかります。 最終的に下記のエラー(HTML関係)が表示されますが、HTMLはひとまず使用しないので気にしないでおきます。

error.png

Figure 6: HTMLのエラー

3.2 PC版を動かす

インポートが終わったら、早速実行してみます。

  • メニュー → Run → Edit Configrationsを選択。

Run-DebugConfigurations_012.png

入力内容は以下のとおり。

Name Desktop
Use class path of module desktop
Main class DesktopLauncher クラスを選択
Working directory android/assetsディレクトリを選択

最後にOKを選択します。

実行環境が作成できたら、右上にあるIntelliJのセレクトボックスからDesktopを選択して再生ボタンを押下します。 最初の実行は、インポート以上に時間がかかりますので心してください。

run.png

Figure 8: 右上にあるセレクトボックス

下記の画面が表示されたら成功です!おめでとうございます!!

sample.png

Figure 9: 実行画面

3.3 Android版を動かす

  • デバイスを接続します。
    • 予めOSがきちんと認識していることを確かめておいて下さい。
  • 右上のセレクトボックスから「android」を選択し、再生ボタンを押下します。
  • 認識しているデバイスが表示されるので、選択して実行します。

3.4 HTML版を動かす

ターミナルを開きます。

メニュー → View → Tool Windows → Terminal

ターミナルでプロジェクトルートに移動します。

$ cd ~/dev/libtext

下記のコマンドを実行します。

$ ./gradlew html:superDev

いろいろ出力が表示され、最終的に The code server is ready. の表示がされたら、 下記にアクセスします。

terminal.png

Figure 10: Terminal

HTML版は、 String.format メソッドが使えなかったり、 BitmapFontが表示できなかったり制限があるので注意してください。

html.png

Figure 11: HTML版を起動している様子

4 Eclipseで使う

Juno4.2、日本語版で解説します。

4.1 Gradleプラグインのインストール

  • メニュー → ヘルプ → 新規ソフトウェアのインストール
  • 作業対象欄に下記を入力し、追加ボタンを押下
  • ダイアログの名前欄に「Gradle」と入力し、OKボタンを押下
  • 「Extensions / Gradle Integration」をチェックし、「次へ」ボタンを押下
  • 「次へ」ボタンを押下
  • 「使用条件の条項に同意します」をチェックし、「完了」ボタンを押下

4.2 プロジェクトのインポート

  • メニュー → ファイル → インポート → Gradel Project → 次へボタンを押下
  • ルートフォルダー欄に、生成したプロジェクトディレクトリを入力、BuiildModeボタンを押下
  • プロジェクト欄の最上意プロジェクトを選択して、完了ボタンを押下

4.3 PC版を動かす

下記の手順です。

  • パッケージエクスプローラから、desktopプロジェクトを選択、右クリック
  • 実行 → Javaアプリケーション を選択
  • 型選択欄で、desktopと入力
  • 一致する項目からDesktopLauncherクラスを選択し、OKボタンを押下

以上で実行されます。

4.4 Android版を動かす

下記の手順です。

  • 事前にデバイスをOSが認識していることを確認してください。
  • パッケージエクスプローラから、androidプロジェクトを選択、右クリック
  • 実行 → Android アプリケーション を選択

以上で実行されます。

4.5 HTML版を動かす

下記の手順です。

  • パッケージエクスプローラから、gwtプロジェクトを選択、右クリック
  • 実行 → 外部ツールの構成
  • 左ペインの「プログラム」をダブルクリック
  • 名前欄に「GWT SuperDev」と入力
  • ローション欄:ファイルシステムの参照ボタンから「gradlew(windowsの場合は、gradlew.bat)」を選択
  • 作業ディレクトリ欄:ファイルシステムの参照ボタンから、プロジェクトルートを選択
  • 引数欄に「html:superDev」と入力
  • 適用ボタンを押下
  • 実行ボタンを押下

するとコンソールビューが表示され、いろいろ出力されます。 最終的に The code server is ready. の表示がされたら、 下記にアクセスします。

5 コマンドラインで使う

コマンドラインで実行する場合は特に準備は不要で、 最初のプロジェクト生成で既に準備は整っています。 Emacserの自分は、この方法が一番好きです。

基本的には、gradlewコマンドでタスクを実行するだけです。 Windowsの場合は、gradlewに、拡張子 .bat を追加して実行してください。

gradlewコマンドは、プロジェクトルートで実行する必要があります。

$ cd ~/dev/libgdxtest

5.1 PC版を動かす

下記のように実行します。

$ ./gradlew desktop:run

5.2 Android版を動かす

予め ANDROID_HOME を定義しておく必要があります。 .bashrc などに記述しておきます。

export ANDROID_HOME=~/opt/adt-bundle-linux-x86_64-20130717/sdk

下記のように実行します。

$ gradlew android:installDebug android:run

5.3 HTML版を動かす

下記のように実行します。

$ ./gradlew html:superDev
  :
  :
The code server is ready.
Next, visit: http://localhost:9876/

いろいろ出力が表示され、最終的に The code server is ready. の表示がされたら、 下記にアクセスします。

HTML版は、 String.format メソッドが使えなかったり、 BitmapFontが表示できなかったり制限があるので注意してください。

6 基本的なクラスについて

gdx-setup.jarで作成される雛形は下記のとおりです。

PROJECT_ROOT
  + android
  + core
  + desktop
  + gradle
  + html
  + ios

環境別にディレクトリが切られ、ゲームロジックそのものは core ディレクトリに記述していきます。 環境ごとのディレクトリにはそれぞれその環境専用の起動クラス(*Launcher.java)が定義されています。 環境に依存するコード(例えば広告表示など)は、この環境別のディレクトリ内に記述してきます。

さて core/src ディレクトリには下記のようなクラスがあります。

package com.zarudama.libgdxtest;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class LibGdxSample extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;

    @Override
    public void create () {
        batch = new SpriteBatch();
        img = new Texture("badlogic.jpg");
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1); //画面を赤で塗りつぶし
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // カラーバッファをクリア
        batch.begin(); // 描画の開始
        batch.draw(img, 0, 0); // テクスチャーを描画
        batch.end(); // 描画の終了
    }
}

これは、 gdx-setup.jar で最初に作られる画像を表示するだけのクラスです。 createメソッドは、アプリ内で一度だけ実行される処理を記述し、 renderは毎フレーム呼びだす処理を記述します。renderはつまりメインループとなります。

ApplicationAdapterクラスは、ApplicationListenerインターフェイスを実装したクラスです。 ApplicationListenerインターフェイスは、libGDXでは必ず実装する必要があるため、 ApplicationAdapterクラスが基本的な実装として用意してあります。 単純なゲームやテストプログラムであれば、 このクラスを継承するだけで良いのですが、 実際のゲーム開発では、画面遷移を伴うことが多いはずです。 なのでApplicationAdapterクラスに代わり Gameクラスを継承することが多くなります。 Gameクラスは、画面遷移を担当するScreenクラスを扱い、 GameクラスもまたApplicationListenerインターフェイスを実装しています。

class.png

Figure 12: ApplicationListenerクラス

SpriteBatchクラスは、libGDXで描画を担当するクラスでこれもまた必ず必要なクラスです。 batch.beginメソッドとbatch.endメソッドの間のdrawメソッドで様々な描画を行ないます。

Textureクラスは名前そのままの画像を扱うクラスです。この例では最もシンプルな画像表示なので、 Textureクラスをそのまま描画していますが、実際には後述するSpriteクラスを介して 使用することが多くなるはずです。

7 文字表示

いろいろテストプログラムを書きたいところですが、 まずは文字が表示できないと状態を把握できません。

libGDXはデフォルトで文字描画をサポートしていますので、それを利用します。

下記のように変更してください。diff形式で表示しています。"+"は追加した行、"-"は削除した行です。

mikio@gnudam:~/dev/libgdxtest$ git diff
diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index ad39967..3c84c72 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -4,17 +4,20 @@ import com.badlogic.gdx.ApplicationAdapter;
 import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.graphics.GL20;
 import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;

 public class LibGdxSample extends ApplicationAdapter {
     SpriteBatch batch;
-    Texture img;
+    BitmapFont font;
+    Texture img;

    @Override
    public void create () {
       batch = new SpriteBatch();
       img = new Texture("badlogic.jpg");
-   }
+      font = new BitmapFont();
+   }

    @Override
    public void render () {
@@ -22,6 +25,7 @@ public class LibGdxSample extends ApplicationAdapter {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(img, 0, 0);
+       font.draw(batch, "Hello libGDX", 200, 400);
        batch.end();
    }

+   @Override
+   public void dispose() {
+       font.dispose();
+       batch.dispose();
+       img.dispose();
+   }

 }

サンプルでは、なぜかリソースを解放する処理が抜けていたので、 disposeメソッドに追加してあります。disposeはアプリケーションの終了処理を記述します。

sample2.png

Figure 13: 実行画面

8 スプライトクラスを使用する。

サンプルでは、Textureクラスを直接描画していましたが、 Textureクラスはあくまで画像そのもののクラスであり、 ゲーム内で直接扱うのには向いていません。

ゆくゆくは拡大縮小したりアニメーションしたりする必要がでてきますので、 そのような操作が扱いやすいSpriteクラスを使用します。

diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index 3c84c72..5ab4749 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -5,18 +5,22 @@ import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.graphics.GL20;
 import com.badlogic.gdx.graphics.Texture;
 import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.Sprite;
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;

 public class LibGdxSample extends ApplicationAdapter {
     SpriteBatch batch;
     BitmapFont font;
     Texture img;
+    Sprite sprite;
     @Override
     public void create () {
         batch = new SpriteBatch();
         font = new BitmapFont();
         img = new Texture("badlogic.jpg");
+        sprite = new Sprite(img);
     }

@@ -24,7 +28,7 @@ public class LibGdxSample extends ApplicationAdapter {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
-       batch.draw(img, 0, 0);
+       sprite.draw(batch);
        font.draw(batch, "Hello libGDX", 200, 400);
        batch.end();
    }

このプログラムを実行しても、見た目の変化はありません。

9 座標系

サンプルプログラムの表示で気づいた方もいるかもしれませんが、libGDXでは座標の原点は左下になります。

座標系に関しては、下記の記事が詳しいです。

要点をまとめると

  • 画面の座標系は左下が原点
  • スプライトの座標系も左下が原点
  • スプライトの拡縮時はまんなかが原点
  • スプライトの回転はまんなかが原点
  • ただしSprite#setOriginを使えば、中心を変更できる
  • BitMapフォントはなぜか左上が原点(注意!)

また、デフォルトで表示されるウィンドウサイズは

PC版 640 x 480
Android版 物理画面サイズ
Html版 480 x 320

となります。

数値の根拠は以下のソースになります。

10 画像を動かす

画像の表示ができたのでさっそく動かしてみます。

diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index 5ab4749..e97625e 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -2,18 +2,20 @@ package com.zarudama.libgdxtest;

 import com.badlogic.gdx.ApplicationAdapter;
 import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input;
 import com.badlogic.gdx.graphics.GL20;
 import com.badlogic.gdx.graphics.Texture;
 import com.badlogic.gdx.graphics.g2d.BitmapFont;
 import com.badlogic.gdx.graphics.g2d.Sprite;
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.math.Vector2;

 public class LibGdxSample extends ApplicationAdapter {
     SpriteBatch batch;
     BitmapFont font;
     Texture img;
     Sprite sprite;
+    Vector2 pos;

     @Override
    public void create () {
@@ -21,14 +23,30 @@ public class LibGdxSample extends ApplicationAdapter {
         font = new BitmapFont();
         img = new Texture("badlogic.jpg");
         sprite = new Sprite(img);
+        pos = new Vector2();
     }

    @Override
    public void render () {
+       if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
+           pos.x -= 1;
+       }
+       if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
+           pos.x += 1;
+       }
+       if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
+           pos.y += 1;
+       }
+       if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
+           pos.y -= 1;
+       }
+       String info = String.format("pos(%f,%f)", pos.x, pos.y);
+
+       sprite.setPosition(pos.x, pos.y);
+
        dx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        sprite.draw(batch);
        batch.draw(sprite, 0, 0);
        font.draw(batch, info, 0, 420);
        font.draw(batch, "Hello libGDX", 200, 400);
        batch.end();
    }

    @Override
    public void dispose() {
        font.dispose();
        batch.dispose();
        img.dispose();
    }

座標を扱うのはベクトルクラスが便利なので、posフィールドを追加しています。

また、今自分がいる場所も把握したいので、info変数にposフィールドの値を設定して描画しています。

sample3.png

Figure 14: spriteを動かす

キーボードの入力を得るには、Gdx.input.isKeyPressedメソッドを利用します。 どのキーかどうかは、Input.Keysの定数で判定できます。

今回は、キーボードだけの例ですが、Androidで入力を扱うには、タッチされた座標を取得する必要があります。 タッチ処理は少し複雑なのでここでは割愛します。

11 効果音を鳴らす

下記のサイトで適当に音を作りました。

次からダウンロードできます。

ダウンロードしたファイルを下記に追加してください。

~/dev/libgdxtest/android/assets/

下記のように変更します。

 mikio@gnudam:~/dev/libgdxtest$ git diff
diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.j
ava
index 5ab4749..cf11ba1 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -2,18 +2,22 @@ package com.zarudama.libgdxtest;

 import com.badlogic.gdx.ApplicationAdapter;
 import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.Input;
+import com.badlogic.gdx.audio.Sound;
 import com.badlogic.gdx.graphics.GL20;
 import com.badlogic.gdx.graphics.Texture;
 import com.badlogic.gdx.graphics.g2d.BitmapFont;
 import com.badlogic.gdx.graphics.g2d.Sprite;
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.math.Vector2;

 public class LibGdxSample extends ApplicationAdapter {
     SpriteBatch batch;
     BitmapFont font;
     Texture img;
     Sprite sprite;
     Vector2 pos;
+    Sound sound;

     @Override
     public void create () {
@@ -21,14 +25,35 @@ public class LibGdxSample extends ApplicationAdapter {
         font = new BitmapFont();
                img = new Texture("badlogic.jpg");
         sprite = new Sprite(img);
         pos = new Vector2();
+        sound = Gdx.audio.newSound(Gdx.files.internal("jump.wav"));
     }

     @Override
     public void render () {
         if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
             pos.x -= 1;
         }
         if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
             pos.x += 1;
         }
         if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
             pos.y += 1;
         }
         if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
             pos.y -= 1;
         }
         String info = String.format("pos(%f,%f)", pos.x, pos.y);

+        if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
+            sound.play();
+        }

         Gdx.gl.glClearColor(1, 0, 0, 1);
         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
         batch.begin();
         batch.draw(sprite, pos.x, pos.y);
         font.draw(batch, info, 0, 420);
         font.draw(batch, "Hello libGDX", 200, 400);
         batch.end();
     }

     @Override
     public void dispose() {
         font.dispose();
+        sound.dispose();
         batch.dispose();
         img.dispose();
     }

soundクラスを使いして、playメソッドを呼ぶだけです。 スペースキー押下でジャンプしたような効果音が鳴ります。 最後にリソースを解放するのを忘れずに。

12 BGMを鳴らす

下記のサイトで適当に曲を作りました。

次からダウンロードできます。

ダウンロードしたファイルを下記に追加してください。

~/dev/libgdxtest/android/assets/

下記のように変更します。

diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index 5ab4749..c345ac8 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -2,18 +2,24 @@ package com.zarudama.libgdxtest;

 import com.badlogic.gdx.ApplicationAdapter;
 import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.Input;
+import com.badlogic.gdx.audio.Music;
 import com.badlogic.gdx.audio.Sound;
 import com.badlogic.gdx.graphics.GL20;
 import com.badlogic.gdx.graphics.Texture;
 import com.badlogic.gdx.graphics.g2d.BitmapFont;
 import com.badlogic.gdx.graphics.g2d.Sprite;
 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
 import com.badlogic.gdx.math.Vector2;

 public class LibGdxSample extends ApplicationAdapter {
     SpriteBatch batch;
     BitmapFont font;
     Texture img;
     Sprite sprite;
     Vector2 pos;
     Sound sound;
+    Music music;

     @Override
    public void create () {
@@ -21,15 +27,48 @@ public class LibGdxSample extends ApplicationAdapter {
         font = new BitmapFont();
        img = new Texture("badlogic.jpg");
         sprite = new Sprite(img);
         pos = new Vector2();
         sound = Gdx.audio.newSound(Gdx.files.internal("jump.wav"));
+        music = Gdx.audio.newMusic(Gdx.files.internal("mixdown.mp3"));
+        music.setLooping(true);
+        music.setVolume(0.5f);
+        music.play();
     }


     @Override
     public void dispose() {
         font.dispose();
         sound.dispose();
+        music.dispose();
         batch.dispose();
         img.dispose();
     }
 }

これもMusicクラスを使用して、playメソッドを呼ぶだけです。 ただしBGMなので、ループフラグを有効にし、ボリュームを控えめにしています。 簡単ですね。最後にリソースを解放するのを忘れずに。

13 画像を拡大・縮小・回転してみる

最後に、せっかくスプライトクラスを使っているので、拡縮を試してみます。

下記のように変更してください。

diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index e52752e..1c12907 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -20,6 +20,7 @@ public class LibGdxSample extends ApplicationAdapter {
     Vector2 pos;
     Sound sound;
     Music music;
+    float angle;

     @Override
     public void create () {
@@ -55,11 +56,15 @@ public class LibGdxSample extends ApplicationAdapter {
	 if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
	     sound.play();
	 }
	 sprite.setPosition(pos.x, pos.y);
+        sprite.setScale((float) Math.sin(angle));
+        angle += 0.04;

	 Gdx.gl.glClearColor(1, 0, 0, 1);
	 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
	 batch.begin();
	 sprite.draw(batch);
	 font.draw(batch, info, 0, 420);
	 font.draw(batch, "Hello libGDX", 200, 400);
	 batch.end();

angle フィールドを追加し、 Sprite#setScale メソッドで拡縮しています。 sclae値としてマイナスを与えると、画像が反転するようです。

sample4.png

Figure 15: spriteを拡縮

ついでに回転させてみます。

diff --git a/core/src/com/zarudama/libgdxtest/LibGdxSample.java b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
index 1c12907..696c158 100644
--- a/core/src/com/zarudama/libgdxtest/LibGdxSample.java
+++ b/core/src/com/zarudama/libgdxtest/LibGdxSample.java
@@ -17,6 +17,7 @@ public class LibGdxSample extends ApplicationAdapter {
     BitmapFont font;
     Texture img;
     Sprite sprite;
+    Sprite sprite2;
     Vector2 pos;
     Sound sound;
     Music music;
@@ -28,6 +29,7 @@ public class LibGdxSample extends ApplicationAdapter {
	 font = new BitmapFont();
	 img = new Texture("badlogic.jpg");
	 sprite = new Sprite(img);
+        sprite2 = new Sprite(img);
	 pos = new Vector2();
	 sound = Gdx.audio.newSound(Gdx.files.internal("jump.wav"));
	 music = Gdx.audio.newMusic(Gdx.files.internal("mixdown.mp3"));
@@ -60,11 +62,14 @@ public class LibGdxSample extends ApplicationAdapter {
	 sprite.setScale((float) Math.sin(angle));
	 angle += 0.04;

+        sprite2.setPosition(200, 300);
+        sprite2.setRotation(angle);
+
	 Gdx.gl.glClearColor(1, 0, 0, 1);
	 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
	 batch.begin();
	 sprite.draw(batch);
+        sprite2.draw(batch);
	 font.draw(batch, info, 0, 420);
	 font.draw(batch, "Hello libGDX", 200, 400);
	 batch.end();

効果がわかりにくいので、sprite2フィールドを追加し、 スプライトを2つにしました。 このようにスプライトを追加しても画像は共有できます。 回転は、Sprite#setRotationメソッドで実施しています。

sample5.png

Figure 16: spriteを回転

これ以上の詳しいSpriteクラスの操作は下記のAPIマニュアルを参照してください。

14 ソース

最後にソースの全体を載せておきます。

package com.zarudama.libgdxtest;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;

public class LibGdxSample extends ApplicationAdapter {
    SpriteBatch batch;
    BitmapFont font;
    Texture img;
    Sprite sprite;
    Sprite sprite2;
    Vector2 pos;
    Sound sound;
    Music music;
    float angle;

    @Override
    public void create () {
        batch = new SpriteBatch();
        font = new BitmapFont();
        img = new Texture("badlogic.jpg");
        sprite = new Sprite(img);
        sprite2 = new Sprite(img);
        pos = new Vector2();
        sound = Gdx.audio.newSound(Gdx.files.internal("jump.wav"));
        music = Gdx.audio.newMusic(Gdx.files.internal("mixdown.mp3"));
        music.setLooping(true);
        music.setVolume(0.5f);
        music.play();
    }

    @Override
    public void render () {
        if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
            pos.x -= 1;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
            pos.x += 1;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
            pos.y += 1;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
            pos.y -= 1;
        }
        //String info = String.format("pos(%f,%f)", pos.x, pos.y);
        String info = ""; //html版ではコンパイルできない。

        if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
            sound.play();
        }
        sprite.setPosition(pos.x, pos.y);
        sprite.setScale((float) Math.sin(angle));
        angle += 0.04;

        sprite2.setPosition(200, 300);
        sprite2.setRotation(angle);

        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        sprite.draw(batch);
        sprite2.draw(batch);
        font.draw(batch, info, 0, 420);
        font.draw(batch, "Hello libGDX", 200, 400);
        batch.end();
    }

    @Override
    public void dispose() {
        sound.dispose();
        music.dispose();
        batch.dispose();
        font.dispose();
        img.dispose();
    }
}

15 おわりに

この記事ではゲームプログラミングに最低限必要な以下の方法を学びました。

  • 画像の表示
  • キーボードの入力
  • サウンド・BGMの再生

これで一応ゲームは開発できるはずです。 でもこれは最低限の方法なので、まだまだいろいろ考慮しなくてはなりません。 例えば、

  • タッチ処理
  • アニメーション
  • 物理画面に依存しない画面表示
  • 画面遷移

などなどです。 次回 は、これらの処理を学んでいきます。

16 参考書籍

libGDXの作者が書いた本。Androidでゲームを作るための基本を独自のフレームワーク作成を通して解説しています。 libGDXの解説ではないけれど、その思想は当然libGDXにも引き継がれています。もちろんlibGDXの理解もしやすくなります。 また、Androidの本ではありますが、スマホに特化したわけでもなく、 どんなゲーム開発にも通用しそうな内容ばかりです。 実践的かつ基本的で自分は退屈せずに読めました(特にMVCについての言及が良い)。 そういう意味でこの本は、すべての初級ゲーム開発者におすすめできる本かと思います。 ただし一部内容が古いので注意してください(沢山売れて第2版が翻訳されればいいんですが)。 それでもlibGDXをやるなら読んでいて損はないと思います。

blog comments powered by Disqus