SunのMIDP2.0ではPNG画像がマンダトリ(必須)要件となっており、PNG画像でしたら必ず出来ることになっています。OAPではこれに加えJPEG画像もサポートしています。
OAPがサポートしているPNG画像は8ビット、24ビットのPNG画像、もしくは8ビットの2値透過画像になります。従って通常では8ビットの2値透過画像を使うことになると思います。αチャンネル(半透明)は対応していません。
私の場合、PhotoShopで透過PNGを作成していると上手く行かないので、GIMPを使って8ビットのαチャンネル無し画像に落としています。
PNG画像、JPEG画像共にImageクラス、Spriteクラス等で描画できます。どちらも単に描画するだけなら殆ど同じコードで書けます。Spriteは単なるイメージを扱うだけでなく、色々と便利な機能が提供されています。
Imageクラス(javax.microedition.lcdui.Image)を利用してPNG画像、JPEG画像のデコード、表示が出来ます。これを使って今表示されている画面の壁紙を書いてみます。背景はこんな画像を使ってみます。
画像はプロジェクトファイル内部のres下に入れておくと、アプリからアクセスできるようになります。
Project root
├─bin
├─classes
├─lib
├─res ←ここに画像やMIDI等のリソースファイルを入れる
├─src
├─tmpclasses
└─tmplib
SkeltonのCanvasクラスを少し変更します。(wallpaper.zip)
class mycanvas extends Canvas { Image imgWallPaper; /* 壁紙 */ mycanvas() { try { imgWallPaper = Image.createImage("/haikei.png"); } catch( Exception e ) { System.out.println( "error" + e.toString() ); } } public void paint( Graphics g ) { // g.setColor( 255, 255, 255 ); // g.fillRect( 0, 0, getWidth(), getHeight() ); // 壁紙をタイリング表示 for ( int yy = 0; yy < getHeight(); yy += imgWallPaper.getHeight() ) { for( int xx = 0; xx < getWidth(); xx += imgWallPaper.getWidth() ) { g.drawImage( imgWallPaper, xx, yy, g.LEFT|g.TOP ); } } g.setColor( 0, 0, 0 ); g.drawString("This is Skelton app", 0, 0, Graphics.LEFT|Graphics.TOP); } public void keyPressed( int keycode ) { switch ( getGameAction( keycode ) ) { case FIRE: repaint(); break; default: break; } } }
これで画面いっぱいに壁紙が表示されるはずです。
スプライトでも同様に画像の表示が出来ますが、もう少し便利な使い方が色々出来ます。主にアニメーションの表示に使われますが、ここではスプライトが持つ機能を使ってビットマップ文字列を書いてみます。ゲームを作っていると、独自フォントで文字を書いているアプリを時々見かけますが、そういったアプリに最適です。
漢字はさすがにキツイので、ASCII文字に対象を絞ります。
以下の様な画像を用意します。
これはASCII文字の可視部分に当たる32〜127までの文字を3列に記したものです。(※127は少し細工してあります。)
FontはSR*Jupiterというものです。ここのものを利用しています。
スプライトの作成は以下の様にします。
Sprite sprFont16;
sprFont16 = new Sprite( Image.createImage( "/font16.png" ), FONTSIZE_DX, FONTSIZE_DY );
このフォントは16×10ドットで作成してあります。なので、FONTSIZE_DX、FONTSIZE_DYにはそれぞれ16と10が入っています。
これだけで文字を表示するための画像は準備完了です。
次に作成したスプライトを切り出して文字を表示する関数を作ります。
public void drawSpriteString( Graphics g, String istr, int ix, int iy ) { char cc; try{ for( int ii = 0; ii < istr.length(); ii++ ) { cc = istr.charAt( ii ); // 文字列を順番に取り出す sprFont16.setFrame( (int)cc - 32 ); // 取り出したASCIIコードから32を引いて場所をそろえる sprFont16.setPosition( (ix+ii) * FONTSIZE_DX, iy * FONTSIZE_DY ); sprFont16.paint( g ); } }catch( Exception e ){} }
これで文字列を表示する事が可能となりました。スプライトは自動的に画像を分割してインデックス値で取り出すことが出来ますので、こういった処理には(外道かもしれませんが)便利です。
スプライトの置き場所ですが、将来的に複数のCanvasクラスから参照されることを想定して、MIDletクラス内に配置するのが良いと思います。各CanvasクラスからMIDletクラスへのアクセスは別途記載します。
全体的なコードは以下の様になりました。(fontimage.zip)
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; // Spriteに必要 public final class applet extends MIDlet implements CommandListener { private static Command cmdExit = new Command("Exit", Command.EXIT,1); private static Display display; // Font public static final int FONTSIZE_DX = 10; public static final int FONTSIZE_DY = 16; static Sprite sprFont16; /* ----------------------------------------------------------------------*/ public applet() { display = Display.getDisplay(this); mycanvas canvas = new mycanvas(); canvas.addCommand(cmdExit); canvas.setCommandListener(this); display.setCurrent( canvas ); try { sprFont16 = new Sprite( Image.createImage( "/font16.png" ), FONTSIZE_DX, FONTSIZE_DY ); } catch( Exception e ) {} } /* ----------------------------------------------------------------------*/ public void startApp() { } /* ----------------------------------------------------------------------*/ public void pauseApp() { } /* ----------------------------------------------------------------------*/ public void destroyApp( boolean flag ) { } /* ----------------------------------------------------------------------*/ public void commandAction(Command c, Displayable d) { try { destroyApp(true); notifyDestroyed(); } catch ( Exception e) {} } } class mycanvas extends Canvas { mycanvas() {} /* ----------------------------------------------------------------------*/ public void paint( Graphics g ) { g.setColor( 255, 255, 255 ); g.fillRect( 0, 0, getWidth(), getHeight() ); g.setColor( 0, 0, 0 ); drawSpriteString( g, "This is Skelton app", 0, 0 ); } //* -------------------------------------------------------- */ public void drawSpriteString( Graphics g, String istr, int ix, int iy ) { char cc; try{ for( int ii = 0; ii < istr.length(); ii++ ) { cc = istr.charAt( ii ) ; applet.sprFont16.setFrame( (int)cc-32 ); applet.sprFont16.setPosition( (ix+ii) * 10, iy * 16 ); applet.sprFont16.paint( g ); } }catch( Exception e ){} } }
結果は以下の様になります。
ゲームアプリでは点数の表示を行う必要があります。上記の文字列表示を応用して、スコアを表示するときには以下の様な関数を作ればよいと思います。
public void draw4Int( int in, int ix, int iy ) { int index; try { for( int ii = 3; ii >= 0; ii-- ) { index = in % 10; applet.sprFont16.setFrame( index+16 ); applet.sprFont16.setPosition( (ix+ii) * 10, iy * 16 ); applet.sprFont16.paint( g ); in /= 10; } } catch( Exception e ) { System.out.println(e.toString()); } }