対象とする各プラットフォームごとに、起動クラスを記述する必要があります。
このクラスでは、バックエンドで動くApplication
固有の実装と、アプリケーションのロジックを実装するApplicationListener
のインスタンスを作成します。
起動クラスはプラットフォームごとに違っています。各バックエンドでインスタンスを作成して設定する方法を見てみましょう。
この記事では、あなたが既にプロジェクトの設定、実行、デバッグの説明に従って作業を完了し、 生成されたコアプロジェクト、デスクトップ用プロジェクト、Android用プロジェクト、HTML5プロジェクトをEclipseにインポートしているものと想定しています。
my-gdx-game
内にあるMain.java
クラスを開くと以下の内容が表示されます:
package com.me.mygdxgame; import com.badlogic.gdx.backends.lwjgl.LwjglApplication; import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; public class Main { public static void main(String[] args) { LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration(); cfg.title = "my-gdx-game"; cfg.useGL30 = false; cfg.width = 480; cfg.height = 320; new LwjglApplication(new MyGdxGame(), cfg); } }
最初の行では、LwjglApplicationConfiguration のインスタンスを作成しています。 このクラスでは、初期画面の解像度、OpenGL ES 2.0 や 3.0 (Experimental)を使用するかどうかなど、各種構成設定を指定できます。 詳細情報についてはこのクラスの Javadocs を参照してください。
configuration オブジェクトの設定が済んだら、LwjglApplication
のインスタンスを作成します。
MyGdxGame()
クラスは、ゲームのロジックを実装した ApplicationListener です。
その後ウィンドウが作成され、 ライフサイクルで説明したようにApplicationListenerが起動されます。
準備中...
Android アプリケーションはmain()
メソッドをエントリポイントとして使用しませんが、代わりに Activityが必要です。
my-gdx-game-android
プロジェクト内の MainActivity.java
クラスを開いてください:
package com.me.mygdxgame; import android.os.Bundle; import com.badlogic.gdx.backends.android.AndroidApplication; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; public class MainActivity extends AndroidApplication { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration(); initialize(new MyGdxGame(), cfg); } }
Activityの onCreate()
メソッドが、エントリポイントとなるmain メソッドの役目を果たします。
MainActivity
は AndroidApplication
を継承しており、そのAndroidApplication
はActivity
を継承しているので覚えておいてください。
デスクトップの起動クラスと同じように。 configuration インスタンス (AndroidApplicationConfiguration)を作成します。
設定が済んだら、 設定情報とApplicationListener
であるMyGdxGame
を引数として渡してAndroidApplication.initialize()
メソッドを実行します。
どういった構成設定が使用できるかの詳細情報については、 AndroidApplicationConfiguration Javadocsを参照してください。
Android アプリケーションでは複数のActivityを使用することができます。 Libgdx 製のゲームは通常一つのActivityのみで作成するようにしてください。
libgdxには、Activityを分けなくても異なる画面を切り替えられる処理が実装されています。
これは、新規にActivity
を作成すると必然的に新規OpenGLコンテキストも作成することになるためです。
それだと時間がかかるうえに多くのグラフィックリソースを再読み込みする必要がでてきてしまいます。
Android SDK では、特定の画面一部のコントローラーを作成するためのAPIが導入されました。これにより、複数の画面で画面パーツの使い回しが簡単にできます。
この API は Fragments APIと呼ばれています。
Libgdx もFragment内の画面の一部として使用できます。
Libgdx fragmentを作成するには、AndroidFragmentApplication
のサブクラスを作って以下のような初期化処理を行うonCreateView()
を実装します:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return initializeForView(new MyGdxGame());
}
このコードを正常に動かすには、 -android projectへ他にいくつか変更が必要です。:
例えば:
// 2. Change AndroidLauncher activity to extend FragmentActivity, not AndroidApplication // 3. Implement AndroidFragmentApplication.Callbacks on the AndroidLauncher activity public class AndroidLauncher extends FragmentActivity implements AndroidFragmentApplication.Callbacks { @Override protected void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 6. Finally, replace the AndroidLauncher activity content with the Libgdx Fragment. GameFragment fragment = new GameFragment(); FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); trans.replace(android.R.id.content, fragment); trans.commit(); } // 4. Create a Class that extends AndroidFragmentApplication which is the Fragment implementation for Libgdx. private class GameFragment extends AndroidFragmentApplication { // 5. Add the initializeForView() code in the Fragment's onCreateView method. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return initializeForView(new MyGdxGame()); } } @Override public void exit() {} }
AndroidApplicationConfiguration
以外に、 Android アプリケーションは AndroidプロジェクトのルートディレクトリにあるAndroidManifest.xml
ファイルでも設定できます。この設定は以下のようになります:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.me.mygdxgame" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="landscape" android:configChanges="keyboard|keyboardHidden|orientation"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
この属性には対象とするAndroidのバージョンを設定します。
targetSdkVersion属性に加えて、 activityの要素には screenOrientation
属性と configChanges
属性を常に設定する必要があります。
screenOrientation
属性では、アプリケーション用に画面の縦横向きを固定します。
アプリケーションが横向きモードと縦向きモードの両方で動作する場合はこれを省略してかまいません。
The configChanges
attribute is crucial and should always have the values shown above.
この属性を設定しないと、物理キーボードが接続状態/非接続状態になる度に、または端末の傾きが変更になった場合にアプリケーションが再起動します。
screenOrientation
属性が省略された場合、libgdx アプリケーションは画面向きの変更を生じさせるApplicationListener.resize()
へのコールを受信するようになります。 API クライアントではそれを受けてアプリケーションの再レイアウトをおこなうことができます。
アプリケーションが端末の外部ストレージ(例えばSDカード)に書き込みをできるようにする必要がある場合、インターネットアクセスが必要な場合、バイブレーターを使用する場合、音声録音をしたい場合は、以下のパーミッションをAndroidManifest.xml
ファイルに追加する必要があります:
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.VIBRATE"/>
ユーザーは多くのパーミッションが必要なアプリケーションを普通は怪しく思うので、どのパーミッションを要求するかは賢明に判断してください。
ロック復帰機能を有効にする場合は、AndroidApplicationConfiguration.useWakeLock
に trueを設定する必要があります。
ゲームで加速度センサーとコンパスへのアクセスが不要な場合は、AndroidApplicationConfiguration
のuseAccelerometer
フィールドとAndroidApplicationConfiguration
フィールドにfalseに設定してこれらを無効にすることをお勧めします。
ゲームでジャイロセンサーが必要な場合は、AndroidApplicationConfiguration
内のuseGyroscope
にtrueを設定する必要があります。
(これは電力を節約するために既定では無効になっています)。
アプリケーションのアイコンなどのようなその他の属性を設定する方法の詳細情報についてはAndroid 開発者ガイドを参照してください。
Libgdx にはAndroidの ライブ壁紙を簡単に作成する機能があります。
ライブ壁紙の起動クラスはAndroidLiveWallpaperService
と呼ばれ、以下がその例になります:
package com.mypackage; // imports snipped for brevity public class LiveWallpaper extends AndroidLiveWallpaperService { @Override public ApplicationListener createListener () { return new MyApplicationListener(); } @Override public AndroidApplicationConfiguration createConfig () { return new AndroidApplicationConfiguration(); } @Override public void offsetChange (ApplicationListener listener, float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { Gdx.app.log("LiveWallpaper", "offset changed: " + xOffset + ", " + yOffset); } }
createListener()
メソッドと createConfig()
メソッドは、ライブ壁紙がpicker内に表示された時やホームスクリーン上で表示された場合に呼び出されます。
offsetChange()
メソッドはユーザーが画面をスワイプした時に呼び出され、画面が中央からどれだけ相対移動したかを通知します。
このメソッドは描写スレッドで呼び出されるので、同期処理を行う必要はありません。
起動クラスに加えて、壁紙について記述した XML ファイルを作成する必要があります。
そのファイル名は livewallpaper.xmlとしましょう。Androidプロジェクトのres/
フォルダ内にxml/
という名前のフォルダを作成して、そのファイルを置きます(res/xml/livewallpaper.xml
)。以下がファイルに記述する内容になります:
<?xml version="1.0" encoding="UTF-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:thumbnail="@drawable/ic_launcher" android:description="@string/description" android:settingsActivity="com.mypackage.LivewallpaperSettings"/>
これはpicker内のライブ壁紙を表示するサムネイル、ライブ壁紙に関する説明、ユーザーがライブ壁紙picker内の"Settings"をタップした時に表示されるActivityを定義しています。
ここでは、背景色などのような設定を変更するためのいくつかのウィジットを持つ標準Activityを設定します。
このActicityで変更した設定情報はSharedPreferences内に保存して、後からGdx.app.getPreferences()
を使ってライブ壁紙のApplicationListenerに読み込むことができます。
最後にこれらを AndroidManifest.xml
ファイルに追加する必要があります。以下は、簡単な settings Activityを付けたライブ壁紙の例です:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mypackage" android:versionCode="1" android:versionName="1.0" android:installLocation="preferExternal"> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14"/> <uses-feature android:name="android.software.live_wallpaper" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".LivewallpaperSettings" android:label="Livewallpaper Settings"/> <service android:name=".LiveWallpaper" android:label="@string/app_name" android:icon="@drawable/icon" android:permission="android.permission.BIND_WALLPAPER"> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/livewallpaper" /> </service> </application> </manifest>
このマニフェストでは以下を定義しています:
<uses-feature>
の部分を参照。android:permission
の部分を参照。meta-data
の部分を参照。
ライブ壁紙はAndroid 2.1 (SDK level 7)以降でのみサポートを開始しているので注意してください。
ライブ壁紙にはタッチ入力に関するいくつかの制限があります。通常はタップ/ドロップのみしか通知されません。
タッチ機能を全ての使用したい場合は、AndroidApplicationConfiguration#getTouchEventsForLiveWallpaper
フラグをtrueにするとマルチタッチイベントを全て受信できます。
Android 4.2から、ユーザーは端末が待機状態やドック画面になった場合に表示されるDaydreams を設定できるようになりました。 これらDaydreamはスクリーンセーバーのようなもので、写真アルバムなどを表示することができます。 Libgdx ではそうした daydreams などを簡単に記述できます。
Daydream の起動クラスは AndroidDaydreamと呼ばれます。以下がその例です:
package com.badlogic.gdx.tests.android; import android.annotation.TargetApi; import android.util.Log; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; import com.badlogic.gdx.backends.android.AndroidDaydream; import com.badlogic.gdx.tests.MeshShaderTest; @TargetApi(17) public class Daydream extends AndroidDaydream { @Override public void onAttachedToWindow() { super.onAttachedToWindow(); setInteractive(false); AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration(); ApplicationListener app = new MeshShaderTest(); initialize(app, cfg); } }
AndroidDaydreamを継承して onAttachedToWindowを上書きし、configurationと ApplicationListener を設定して daydreamを初期化するだけです。
daydream自身に加えて、ユーザーがdaydreamを設定できるようにする設定用アクティビティを用意することができます。
これには普通のactivityやlibgdx のAndroidApplication
が使用できます。以下が、雛形となる空activity の例です:
package com.badlogic.gdx.tests.android; import android.app.Activity; public class DaydreamSettings extends Activity { }
この設定用アクティビティは、Daydream サービスにメタデータとして設定する必要があります。 Androidプロジェクトのres/xmlフォルダ内でxmlファイルを作成して、以下のようなactivityを設定してください:
<dream xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.badlogic.gdx.tests.android/.DaydreamSettings" />
最後に、いつものように AndroidManifest.xmlにsettings activityの項目とdaydreamに関するサービス説明を追加してください。以下のように:
<service android:name=".Daydream" android:label="@string/app_name" android:icon="@drawable/icon" android:exported="true"> <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.service.dream" android:resource="@xml/daydream" /> </service>
準備中..
HTML5/GWT アプリケーションのメインエントリーポイントは GwtApplication
です。my-gdx-game-html5プロジェクト内の GwtLauncher.java
を開いてください:
package com.me.mygdxgame.client; import com.me.mygdxgame.MyGdxGame; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.backends.gwt.GwtApplication; import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration; public class GwtLauncher extends GwtApplication { @Override public GwtApplicationConfiguration getConfig () { GwtApplicationConfiguration cfg = new GwtApplicationConfiguration(480, 320); return cfg; } @Override public ApplicationListener createApplicationListener () { return new MyGdxGame(); } }
メインエントリーポイントは GwtApplication.getConfig()
と GwtApplication.createApplicationListener()
という二つのメソッドで構成されています。
GwtApplication.getConfig()
メソッドを上書きする際には、HTML5アプリケーションの様々な構成設定を師弟したGwtApplicationConfigurationインスタンスを戻り値として返す必要があります。
GwtApplication.createApplicatonListener()
メソッドを上書きする際には、実行するための ApplicationListener
を戻り値として返す必要があります。
GWT では参照する各 jar/project ごとに実際の Java コードが必要です。さらに、これらの各 jars/project にはファイル名の末尾が gwt.xmlとなっているモジュール定義ファイルを持っている必要があります。
例えばプロジェクトの設定では、 html5 project のモジュールファイルは以下のようになります:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd"> <module> <inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' /> <inherits name='MyGdxGame' /> <entry-point class='com.me.mygdxgame.client.GwtLauncher' /> <set-configuration-property name="gdx.assetpath" value="../my-gdx-game-android/assets" /> </module>
この設定では、開始点クラスとhtml5 projectのルートディレクトリへの相対パス(assetsディレクトリを指している)だけではなく、継承元となっているその他二つのモジュール(gdx-backends-gwt と core project)も設定しています。
Both the gdx-backend-gwt jar and the core project have a similar module file, specifying other dependencies. モジュールのファイルとソースが含まれていない jars/project を使用することはできません!
モジュールと依存関係の詳細情報については、GWT 開発者ガイドを参照してください。
様々な理由から、GWT では Java リフレクションをサポートしていません。 Libgdx は、選ばれた小数の内部クラスについて、リフレクション情報を生成をする内部エミュレーションレイヤを持っています。 つまり、libgdxのJson のシリアライズ機能を使おうとした場合にこの問題に直面するということです。 リフレクション情報を生成するパッケージとクラスを指定することで、この問題を回避できます。 これを行うためには、GWTプロジェクトのgwt.xmlファイルに以下のような設定プロパティを記述します:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <module> ... other elements ... <extend-configuration-property name="gdx.reflect.include" value="org.softmotion.explorers.model" /> <extend-configuration-property name="gdx.reflect.exclude" value="org.softmotion.explorers.model.HexMap" /> </module>
extend-configuration-property エレメントをさらに追加することで、複数のパッケージやクラスを追加できます。
この機能は試験的に導入されているものなので、ご使用については自己責任でお願いします。
libgdx HTML5 アプリケーションでは、gdx.assetpath
にある全てのゲーム素材を事前に読み込みます。
この読み込み処理の間、GWTウィジットで実装されたローディング画面が表示されます。
このローディング画面をカスタマイズしたい場合は、(上記例のGwtLauncher
で)GwtApplication.getPreloaderCallback()
メソッドを上書きするだけでできます。
以下の例では、Canvasを使って非常にシンプルで雑なローディング画面を描写しています:
long loadStart = TimeUtils.nanoTime(); public PreloaderCallback getPreloaderCallback () { final Canvas canvas = Canvas.createIfSupported(); canvas.setWidth("" + (int)(config.width * 0.7f) + "px"); canvas.setHeight("70px"); getRootPanel().add(canvas); final Context2d context = canvas.getContext2d(); context.setTextAlign(TextAlign.CENTER); context.setTextBaseline(TextBaseline.MIDDLE); context.setFont("18pt Calibri"); return new PreloaderCallback() { @Override public void done () { context.fillRect(0, 0, 300, 40); } @Override public void loaded (String file, int loaded, int total) { System.out.println("loaded " + file + "," + loaded + "/" + total); String color = Pixmap.make(30, 30, 30, 1); context.setFillStyle(color); context.setStrokeStyle(color); context.fillRect(0, 0, 300, 70); color = Pixmap.make(200, 200, 200, (((TimeUtils.nanoTime() - loadStart) % 1000000000) / 1000000000f)); context.setFillStyle(color); context.setStrokeStyle(color); context.fillRect(0, 0, 300 * (loaded / (float)total) * 0.97f, 70); context.setFillStyle(Pixmap.make(50, 50, 50, 1)); context.fillText("loading", 300 / 2, 70 / 2); } @Override public void error (String file) { System.out.println("error: " + file); } }; }
ローディング画面の表示では、純正GWTの機能のみを使用できます。libgdxのAPIは事前読み込みが完了した後にしか使用できないので注意してください。