サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

HELLO WORLD

「全てのチュートリアルはHello Worldで始まらなければならない」という、古くからの決まりごと(おそらく人間の寿命よりも古い)があります。 決まりごとを遵守することが私の取り柄なので、 Hello World アプリを作成しましょう。 Hello World とは作成可能な最も簡単なプログラムの一つであり、画面に Hello Worldの文字を表示するだけです。 もちろん、簡単といっても色々と紆余曲折はあると思いますが、それはそれで面白いです!

始めるにあたり、 前回のチュートリアルで説明したプロジェクトセットアップツールを使って簡単なプロジェクトを作成しました。

直ちにコーディングに移りますが、まずはプロジェクトツールgdx-setup-uiで作成されたコードを簡単に見てみましょう。 プロジェクトは以下のようになっています:

image

見て分かるように、ファイル名はプロジェクトセットアップツールで入力したものに応じて変わります。 注意すべき重要な点は、コードがどのように配置されているかの基礎です。 名前の後ろに何も付いていないフォルダー ( hello-world )は、共有コードを記述する場所です。 名前の後ろに –androidや –desktop や –html と付いているフォルダーはプラットフォーム固有のコードを記述する場所で、上手くいけばこれらを使用する機会は必要最小限だけで済むでしょう。これらについては簡単に見るだけにして、今のところ大事なのはHelloWorld.java ファイルです。 これはApplicationListener という名前のとても重要なクラスが実装される場所です。以下のようにコードを記述します:

package com.gamefromscratch.helloworld;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class HelloWorld implements ApplicationListener {
    private SpriteBatch batch;
    private BitmapFont font;
    
    @Override
    public void create() {        
        batch = new SpriteBatch();    
        font = new BitmapFont();
        font.setColor(Color.RED);
    }

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

    @Override
    public void render() {        
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        font.draw(batch, "Hello World", 200, 200);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

まず最初に気づくかもしれませんが… Mainがありません! Well there is one and we will take a look at it in a second. 結局のところ、 LibGDX はイベント駆動型のエンジンなのです。 ApplicationListener を実装すると、GDX はいくつかのメソッドを呼び出すようになります。このメソッドには呼び出された状況に応じたコードを記述できます。 render()メソッドはフレーム毎に呼び出されるので、特に支障が無ければイベントループとして考えることができます。 それ以外にも、様々なイベントに対応して呼び出されるメソッドがあります。メソッドには、 create, resize, pause ,resumeがあります。 各メソッドがどのイベントに対応しているかは名前から推察できるでしょう!

コードの大部分は create() メソッド内と render()メソッド内に記述します。 create()メソッドでは SpriteBatchと BitmapFont を新規作成して、フォントの色を赤に設定しています。 SpriteBatchとは3Dライブラリ上で構築された2Dゲームエンジンにおける一般的なactivityで、XNAを使ったことがあれば馴染みがあると思います。 基本的には、LibGDXは内部でOpenGL ( もしくはプラットフォームに応じた WebGL )を使って描写を行っています。 OpenGL では描写時にかなりのオーバヘッドが発生します。 Spritebatch はそうした負荷のかかる処理を全て一つの操作にまとめて、オーバーヘッドの量を減らします。一言で言うと、2D描写がとても速くなるのです。 全ての文字の2DビットマップであるBitmapFont の描写は、まさにそうした負荷のかかる処理です。 BitmapFontの コンストラクタにフォントを設定しない場合、LibGDXに内蔵されている既定のArial-15フォントが使用されます。 このフォントファイルは以下のようなものになります:

image

render() メソッドでは、OpenGL のメソッドglClear() と glClearColor()を呼び出して、画面を白でクリアしています。 glClearColorに設定しているパラメータは、画面をクリアするのに使う 赤、緑、青、アルファ ( 透明度 )の値です。 実際の画面クリアはglClearで行っています。ご存知のように基本的な OpenGL の機能は Gdx.gl を介して使用できますが、一般的にはそうしたローレベルの操作をすることはあまりないでしょう。

次に begin()を呼び出してsprite batchを開始し、それから font.draw メソッドを使ってbatchにテキストを描写します。 draw()に渡しているパラメータは、描写対象のbatch、描写するテキスト、テキストを描写するxy座標です。 このコードを実行すると(hello-world-desktop を右クリックして Run As->Java Application の順で選ぶと)、以下が表示されます:

image

出来ました!  これが Hello Worldです。

注意すべき重要なことは、hello-worldプロジェクトは実行可能なアプリケーションではなく、他のプロジェクトから使用されるライブラリということです。 これをどういう意味なのかを説明しましょう。例えば、 hello-world-desktopのコードを見てください:

image

見てください、 Mainがありました!  このコードを確認してみましょう:

package com.gamefromscratch.helloworld;

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 = "hello-world";
        cfg.useGL20 = false;
        cfg.width = 480;
        cfg.height = 320;
        
        new LwjglApplication(new HelloWorld(), cfg);
    }
}

これがあなたのアプリケーションの実際のエントリーポイント、もしくは、少なくともデスクトップ向けのエントリーポイントです。 ここは、デスクトップ固有の設定を記述する場所です。 ApplicationListenerのインスタンスとLwjgl固有の構成設定を引数として渡してLwjglApplicationオブジェクトを作成し、ゲームを開始します。 Lwjgl に初めて触れる人のために説明しておくと、これはOpenGLの上で動作する Java ベースのゲームラッパで、 LibGDX はこれを使ってデスクトップ環境での描写を行います。 ここ以外の場所では設定はできず、LibGDXがあなたに代わって全てを行います。

LibGDX上でどのようにクロスプラットフォームを実現しているのかを本当に理解するには、–htmlプロジェクトのMainも見てみましょう。 実際には–htmlにMainはありませんが、その代わり GwtLauncher.javaがあります。

image

Gwtとは Google Web Toolkitの略で、ブラウザ上で使用するためにJavaをJavaScriptにコンパイルする、Googleが提供している技術のことです。 これが重要な要素であり、LibGDXはこれを使ってゲームをHTML上で実行します。 警告しておきますが、HTML版の作成では非常に面倒くさいことが多々あります! ですから、HTMLを考慮しないゲームを作るのであれば、このプロジェクトを完全に削除して頭痛の種を減らすことが出来ます。

GwtLauncher.javaを見てみましょう:

package com.gamefromscratch.helloworld.client;

import com.gamefromscratch.helloworld.HelloWorld;
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 getApplicationListener () {
        return new HelloWorld();
    }
}

Look’s a lot like the –desktop project main doesn’t it? 基本的なコンセプトは全く同じで、プラットフォーム固有の構成設定を作成してApplicationListenerのインスタンスを作成します。 ですがGwtApplicationクラスはコールバックベースのクラスなので、デスクトップの時とは少し違って見えるでしょう。 これ以降は、このレベルの作業をすることはほとんどありません。注意すべき重要なことは、GwtApplicationConfigurationに渡される値です… この値は作成されるHTML canvas のサイズを表します。 そのため、画面に表示するHTMLアプリのサイズを変更したい場合はこの値を変更します。

基本的にLibGDX は、ApplicationListenerを使ったクロスプラットフォーム方式のゲームを実装した共通ライブラリを一つ作成することで動作します。 マルチプラットフォームに対応するには、各プラットフォーム用プロジェクトを用意して、その中でプラットフォーム固有のApplication(HTMLを対象とする場合はGwtApplicationインスタンス、デスクトップを対象とする場合はLwjglApplicationインスタンス、Androidを対象とする場合はAndroidApplicationインスタンス)を作成し、それを設定してApplicationListenerへ渡します。 このApplicationクラスがApplicationListenerの各フレームで呼び出されます。 素晴らしいことに、たいていの場合この仕様についてあなたが気にするべきことは何もありません… ですが、LibGDXの裏側で何が行われているのかを理解するのに役立ちます。



それと… GWTについて

私が「GWTは少し面倒くさい」と言ったのを覚えていますか? では、hello-world-htmlアプリケーションを実行した時に何か起こるかを見てみましょう ( hello-world-htmlを右クリック->Run As->Web Application):

image

うーん…  基本的に、今回のコードではGWTが許可していない何かやろうとしているのでしょう。 Eclipseのコンソールパネルを見ると、どういった例外が発生しているのかをもう少し詳しく分かります。

image

HelloWorld.Java の17行目で例外が発生しています:

font = new BitmapFont();

では、ここでは一体何が起こっているのでしょうか? 前に私が「BitmapFontの既定のコンストラクタは内蔵の arial-15フォントを使う」と言ったことを思い出してください。 内蔵と言った場合、そのファイルはプロジェクトに含まれている gdx.jar ファイル内に実際に存在しています。 jar ファイルは実はただのzipファイルのなので、ファイルを抽出するとgdxライブラリ自身を構成するコードと素材を見ることができます。 特に重要なのが \gdx\comadlogic\gdx\utils フォルダで、ここでは他のファイルと一緒にフォントファイルが置かれています:

image

基本的にGwtApplicationがこのファイルにアクセスしようとしますが、そのための権限を持っていません。 今回の教訓はなんでしょうか? クロスプラットフォームは素晴らしい… ですが、常に作業が楽になるというわけではありません! HTMLをサポートする必要がないのであれば、HTMLプロジェクトを作成しないことを推奨します。 HTMLはLibGDXにおいてもっとも脆弱な部分であり、GWTで作業をすると様々な苦行と厄介事を被ることになります 作業量が増えるかもしれません!

そうは言っても、これを修正するのはとても簡単で, and it nicely illustrates how you deal with files between your projects… a process that may not be particularly intuitive.  簡単な解決方法は、arial-15.fntファイルとarial-15 ファイルをプロジェクトに追加して対象の行を変更することです:

font = new BitmapFont();

上記を下記のようにします

font = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"),false);

修正版のBitmapFontコンストラクタでは、BitmapFontで使用したフォントファイルのファイルハンドルを引数として受け取っています。 Gdx.files はファイル操作のために使用され、internal メソッドはプロジェクト内に含まれるファイルのファイルハンドラーを戻り値として返します。 false 引数ではフォントのグラフィックを上下反転しないことを指定しています。

では、こうしたファイルを実際にはどうやってプロジェクトに追加すればよいのでしょうか?これらファイルは、hello-world-androidプロジェクトの assets\data フォルダーに追加します:

image

Finderやエクスプローラーからパッケージエクスプローラー画面内のdataフォルダーへ、単にドラッグ/ドロップするだけでファイルを追加できます。

フォントファイルを追加したので、これで HTML 対象アプリを実行できます:

image

これでLibGDXでの Hello Worldは完了です。 次はHello Worldより高度なものをやります。