CanvasのfillText()メソッドを用いれば、さまざまなスタイルやサイズのテキストを画面に表示できます。まずGraphicsインターフェイスのcreateFont()メソッドでフォントを作成します。
createFont(String fontName, Font.Style style, float size);
このメソッドではフォント名とスタイル、サイズが指定できます。フォントのスタイルにはFontのインナークラスであるFont.Styleの列挙型を指定でき、下記の4つから選べます。
Font.Style.PLAIN Font.Style.BOLD Font.Style.ITALIC Font.Style.BOLD_ITALIC
次にテキストのフォーマットを作成します。このフォーマットには上記で作成したフォントやテキストの表示幅、また右ぞろえや左ぞろえなどのテキストをそろえる位置を指定できます。これらのフォーマットはTextFormatクラスのインスタンスに下記のメソッドを用いて指定します。
withFont(Font font); 【1】 withWrapWidth(float wrapWidth); 【2】 withAlignment(TextFormat.Alignment align); 【3】 withWrapping(float wrapWidth, TextFormat.Alignment align); 【4】
【1】は上記で作成したフォントを設定します。【2】はテキストの表示幅を指定し、【3】は行をそろえる位置を指定します。【4】は【2】と【3】の設定を1つのメソッドで行えます。
【3】と【4】で行のそろえる位置を指定するには、下記のTextFormatのインナークラスであるAlignmentの列挙型を使用します。
TextFormat.Alignment.LEFT TextFormat.Alignment.CENTER TextFormat.Alignment.RIGHT
このテキストフォーマットと表示したいテキストの文字列をGraphicsインターフェイスのlayoutText()メソッドに渡してテキストレイアウトを作成します。
layoutText(String text, TextFormat format);
後はCanvasのfillText()メソッドにこのテキストレイアウトと[x,y]の値を渡すと、Canvasの指定した位置にテキストを表示できます。
fillText(TextLayout text, float x, float y);
また、テキストの色は線や図形と同様、CanvasのsetFillColor()で指定できます。下記がこれらのメソッドを使用したサンプルコードと、サンプルを実行することによって表示される画面です。
package com.playn.sample.core; import static playn.core.PlayN.*; import playn.core.Canvas; import playn.core.CanvasImage; import playn.core.Color; import playn.core.Font; import playn.core.Game; import playn.core.Layer; import playn.core.TextFormat; import playn.core.TextLayout; public class SampleText implements Game { @Override public void init() { String text1 = "Hello PlayN!"; String text2 = "This is a sample to show how to display texts with Google's PlayN!"; CanvasImage canvasImage = graphics().createImage(graphics().width(), graphics().height()); Canvas canvas = canvasImage.canvas(); canvas.setFillColor(Color.rgb(255, 255, 255)); TextLayout textLayout; // 画面 1行目: 文字サイズ設定 textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 10f); canvas.fillText(textLayout, 10, 20); textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 20f); canvas.fillText(textLayout, 160, 20); textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 30f); canvas.fillText(textLayout, 310, 20); // 画面 2行目: 文字色設定 textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 20f); canvas.setFillColor(Color.rgb(255, 0, 0)); canvas.fillText(textLayout, 10, 70); canvas.setFillColor(Color.rgb(0, 255, 0)); canvas.fillText(textLayout, 160, 70); canvas.setFillColor(Color.rgb(0, 0, 255)); canvas.fillText(textLayout, 310, 70); // 画面 3行目: フォント設定 canvas.setFillColor(Color.rgb(255, 255, 255)); textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 20f); canvas.fillText(textLayout, 10, 120); textLayout = createTextLayout(text1, "Museo-300", Font.Style.PLAIN, 20f); canvas.fillText(textLayout, 160, 120); textLayout = createTextLayout(text1, "Courier", Font.Style.PLAIN, 20f); canvas.fillText(textLayout, 310, 120); // 画面 4行目: スタイル設定 textLayout = createTextLayout(text1, "Helvetica", Font.Style.PLAIN, 20f); canvas.fillText(textLayout, 10, 170); textLayout = createTextLayout(text1, "Helvetica", Font.Style.BOLD, 20f); canvas.fillText(textLayout, 160, 170); textLayout = createTextLayout(text1, "Helvetica", Font.Style.ITALIC, 20f); canvas.fillText(textLayout, 310, 170); textLayout = createTextLayout(text1, "Helvetica", Font.Style.BOLD_ITALIC, 20f); canvas.fillText(textLayout, 460, 170); // 画面 5行目以降: 表示幅と行ぞろえの位置設定 textLayout = createTextLayoutWithWrapping(text2, "Helvetica", Font.Style.PLAIN, 20f, 250f, TextFormat.Alignment.LEFT); canvas.fillText(textLayout, 10, 220); textLayout = createTextLayoutWithWrapping(text2, "Helvetica", Font.Style.PLAIN, 20f, 250f, TextFormat.Alignment.CENTER); canvas.fillText(textLayout, 10, 305); textLayout = createTextLayoutWithWrapping(text2, "Helvetica", Font.Style.PLAIN, 20f, 250f, TextFormat.Alignment.RIGHT); canvas.fillText(textLayout, 10, 390); Layer layer = graphics().createImageLayer(canvasImage); graphics().rootLayer().add(layer); } private TextLayout createTextLayout(String text, String fontName, Font.Style fontStyle, float size) { Font font = graphics().createFont(fontName, fontStyle, size); TextFormat textFormat = new TextFormat().withFont(font); return graphics().layoutText(text, textFormat); } private TextLayout createTextLayoutWithWrapping(String text, String fontName, Font.Style fontStyle, float size, float width, TextFormat.Alignment align) { Font font = graphics().createFont(fontName, fontStyle, size); TextFormat textFormat = new TextFormat().withFont(font).withWrapping(width, align); return graphics().layoutText(text, textFormat); } @Override public void paint(float alpha) { } @Override public void update(float delta) { } @Override public int updateRate() { return 25; } }
サンプル内ではcreateTextLayout()とcreateTextLayoutWithWrapping()としてテキストレイアウトを作成するメソッドを作りました。これら2つのメソッドの違いは、createTextLayoutWithWrapping()ではフォント名、スタイル、サイズに加え、テキストの表示幅と行をそろえる位置の指定ができる部分です。
PlayNではマウスのクリックやスマートフォンのタッチによって呼ばれるイベントリスナとして「Pointer」「Mouse」「Touch」があります。Mouseはマウスによるクリックの位置や右クリック・左クリックなどの情報を取得でき、Touchではスマートフォンのタッチによる位置や強さの情報が取得できます。
Pointerリスナは他の2つのリスナに比べると、取得できる情報は少ないのですが、クリックとタッチの両方に対応しています。
PointerリスナではMouseとTouchそれぞれの固有の情報(マウスの右クリック・左クリック、タッチの強さなど)は取得できませんが、共通の情報(クリック/タッチの開始・終了位置やドラッグ情報)は取得できます。そのため、実装において、この共通の情報のみが必要な場合はPointerリスナを使用するだけでPCとスマートフォンの両方に対応できます。
以下がPointerリスナを使用したサンプルプログラムです。
package com.playn.sample.core; import static playn.core.PlayN.*; import playn.core.Canvas; import playn.core.CanvasImage; import playn.core.Color; import playn.core.Game; import playn.core.Layer; import playn.core.Pointer; import playn.core.Pointer.Event; public class SamplePointer implements Game { @Override public void init() { pointer().setListener(new PointerListener()); } @Override public void paint(float alpha) { } @Override public void update(float delta) { } @Override public int updateRate() { return 25; } private class PointerListener implements Pointer.Listener { private Canvas startCanvas; private Canvas endCanvas; private Canvas dragCanvas; public PointerListener() { startCanvas = createCanvas(); endCanvas = createCanvas(); dragCanvas = createCanvas(); } private Canvas createCanvas() { CanvasImage canvasImage = graphics().createImage(graphics().width(), graphics().height()); Canvas canvas = canvasImage.canvas(); canvas.setFillColor(Color.rgb(255, 255, 255)); Layer layer = graphics().createImageLayer(canvasImage); graphics().rootLayer().add(layer); return canvas; } @Override public void onPointerStart(Event event) { startCanvas.clear(); startCanvas.drawText("Pointer start on X: " + event.x() + ", Y:" + event.y(), 10f, 20f); } @Override public void onPointerEnd(Event event) { endCanvas.clear(); endCanvas.drawText("Pointer end on X: " + event.x() + ", Y:" + event.y(), 10f, 35f); } @Override public void onPointerDrag(Event event) { dragCanvas.clear(); dragCanvas.drawText("Pointer drag on X: " + event.x() + ", Y:" + event.y(), 10f, 50f); } } }
このサンプルを実行すると、画面の左上にクリック/タッチの開始・終了位置とドラッグの位置が表示されます。
まずinit()メソッド内でPlayNのpointer()メソッドの返り値にPointer.Listenerインターフェイスを実装したクラス(ここではPointerListenerクラス)をセットします。これによりPointerListenerは画面全体にセットされるため、画面のどこをクリック/タッチしても情報を取得できます。
そしてPointerListenerクラスはPointer.Listenerインターフェイスの抽象メソッドである以下のメソッドを実装しています。
onPointerStart(Event event); 【1】 onPointerEnd(Event event); 【2】 onPointerDrag(Event event); 【3】
【1】はクリックのボタンを下げること(タッチで画面に触れること)によって呼ばれ、【2】はクリックのボタンを上げること(タッチで画面から離れること)によって呼ばれます。【3】はドラッグすることで呼ばれるメソッドであり、ドラッグしている間は何度も呼ばれます。
それぞれのメソッドは引数としてEventを受け取り、そのEventから位置の情報を取得できます。サンプルでは、それぞれのイベントの位置を画面に表示しています。
また、何度も表示情報を書き換えるため、clear()メソッドによりCanvasをクリアしてから表示しています。
マウスのクリックやスクリーンのタッチ以外にもキーボードからの入力によって呼ばれるイベントリスナとしてKeyboardリスナがあります。下記がKeyboardリスナのサンプルコードです。
package com.playn.sample.core; import static playn.core.PlayN.*; import playn.core.Canvas; import playn.core.CanvasImage; import playn.core.Color; import playn.core.Game; import playn.core.Keyboard; import playn.core.Keyboard.Event; import playn.core.Keyboard.TypedEvent; import playn.core.Layer; public class SampleKeyboard implements Game { @Override public void init() { keyboard().setListener(new KeyboardListener()); } @Override public void paint(float alpha) { } @Override public void update(float delta) { } @Override public int updateRate() { return 25; } private class KeyboardListener implements Keyboard.Listener { private Canvas keyDownCanvas; private Canvas keyUpCanvas; private Canvas keyTypedCanvas; public KeyboardListener() { keyDownCanvas = createCanvas(); keyUpCanvas = createCanvas(); keyTypedCanvas = createCanvas(); } private Canvas createCanvas() { CanvasImage canvasImage = graphics().createImage(graphics().width(), graphics().height()); Canvas canvas = canvasImage.canvas(); canvas.setFillColor(Color.rgb(255, 255, 255)); Layer layer = graphics().createImageLayer(canvasImage); graphics().rootLayer().add(layer); return canvas; } @Override public void onKeyDown(Event event) { keyDownCanvas.clear(); keyDownCanvas.drawText("onKeyDown: " + event.key().toString(), 10f, 20f); } @Override public void onKeyUp(Event event) { keyUpCanvas.clear(); keyUpCanvas.drawText("onKeyUp: " + event.key().toString(), 10f, 35f); } @Override public void onKeyTyped(TypedEvent event) { keyTypedCanvas.clear(); keyTypedCanvas.drawText("onKeyTyped: " + event.typedChar(), 10f, 50f); } } }
このサンプルを実行しキーボードでキーを打つと、画面の左上に打たれたキーの情報が表示されます。
このサンプルではKeyboardListenerクラスがKeyboard.Listenerインターフェイスの以下の3つの中小メソッドを実装しています。
onKeyDown(Event event); 【1】 onKeyUp(Event event); 【2】 onKeyTyped(TypedEvent event); 【3】
【1】はキーを打ったときのキーが下がったタイミングで呼ばれ、【2】はキーが上がったタイミングで呼ばれます。【1】と【2】では引数で渡されたEventより、どのキーが押されたか分かります。
ただ、このEventで取得できるキーの値は「Key」という列挙型の値のため、その値をtoString()で画面に表示すると、スペースは「SPACE」、シフトは「SHIFT」などと文字が表示されます。
入力されたキーの値を一般的なキーボードのように表示する場合には【3】が良いと思います。【3】のメソッドは【1】と同じタイミングで呼ばれますが、渡される引数が【1】、【2】とは異なりTypedEventであるため、「typedChar()」メソッドを使用することで、一般的にキーボードをたたいた時に表示される文字がcharの値で取得できます。また、シフトキーを使っての大文字・小文字変換もできます。
今回は、さまざまな図形や画像、テキストなどを画面に表示させる方法や、マウスやスマートフォンのタッチ、キーボードからのインプット情報の取得の仕方などを紹介しました。
次回はオーディオファイルの再生やストレージ機能を使用したデータの保存、インターネットへのアクセスなどを紹介したいと思います。
リトルソフト株式会社 所属。SaaS製品 LSクラウド・ウェアの開発に携わるITエンジニア
中田亮平
San Francisco State University コンピュータ・サイエンス修士課程修了。
自社製品の海外市場展開にむけ国際化対応作業を担当中
高良完彰
早稲田大学大学院政治学研究科修士課程修了。
Androidアプリ開発をきっかけにIT業界に飛び込む
Copyright © ITmedia, Inc. All Rights Reserved.