1.1 初めに
当マニュアルでは、当HPでi-mode javaの基礎を学習された方を対象ととしてiアプリでロールプレイングゲームを作成しながらプログラムを学習しようと言う目的で作成されています。もちろん、当HPでi-mode
javaの基礎を学習をしていなくても相応の知識がある方でもかまいません。これからは、プログラム中級編ですので最初のマニュアルのように細かい解説は行いません。図も少ないと思います。ある程度のところは、自分で解読するようにしてください。
ここでは、当HPのi-mode javaの基礎と重なる解説もありますが復習も兼ねて読む用意してください。また、Canvasクラスの利用についても解説してあります。プログラムを作成するツールとしてdocomoから無償で提供されている「iαppli Development Kit」(Doja2.0)を利用します。以降、このツールの事を「iappliTool」と呼びます。「iappliTool」の使い方は、docomoのマニュアルを参照してください。当HP、i-mode
javaの基礎を解説したページにも基本的な操作の仕方は説明してあります。
iアプリを作成するには、i-mode javaが提供するIApplicationクラスを継承してアプリの本体を作成します。アプリを起動するとIApplicationを継承したクラスからプログラムが実行されます。また、IApplicationクラスだけでは画面にデータを表示することが出来ませんので、PanelクラスとCanvasクラスのどちらかを使用しなければなりません。
当マニュアルでは、Canvasクラスを使用します。すこし、PanelクラスとCanvasクラスのお話をしましょう。PanelクラスとCanvasクラスもi-mode
javaで画面に何かを表示する機能を持ちます。Panelクラスは、高レベルAPIと言われ高機能な分、手軽にプログラムを組むことが出来ます。そして、このマニュアルで使用するCanvasクラスは、低レベルAPIと呼ばれ、使用するに当たっては高レベルAPIよりプログラムが複雑になります。様は、同じような処理を行うにも高レベルAPIは高機能なため簡単に管理できて、低レベルAPIは機能が少ないためプログラムを作成して管理してやら無ければならないのです。
「低レベルAPIは、低機能なのになんでつかうの?」という声が聞こえてきそうですね。低機能というのは色々な機能が実装されてないだけです。例えば、プラモデルでパーツに塗装が済んでいるものと塗装は自分でやらなければならないものがあったとします。どちらが高機能でしょうか?。確かに塗装が済んでいるプラモデルは組み立てるだけで簡単に作ることが出来ます。しかし、好きに塗装は変えれません。かたや、塗装なしのプラモデルは塗装も自分で行わないといけませんが細かい汚れを表現したり、自分好みの色彩にするなど作成側が自由に作り変えることが出来ます。
高レベルAPIと低レベルAPIも同じです。高レベルAPIは、機能が元々ついている分、プログラム作成側は、高レベルAPIの仕様に従わなければなりません。しかし、低レベルAPIは機能が少ないのでプログラムの手間はかかりますが製作側で柔軟に使用することが出来ます。ゲームの目的にもよりますが、自由性に富んだ制御が必要な場合は、Canvasクラスを使用したほうが良いのです。
1.2 Canvasクラスの概要
Canvasクラスが使えないと話が進みません。ここからは、Canvasクラスの基本的な使い方を学んでいきましょう。i-mode
javaを他の書籍などで勉強していてCanvasクラスの使い方は必要ないという方は読み飛ばしてかまいません。
Canvasクラスを使用して文字を表示してみます。iappliToolを起動して、SampleCav1というプロジェクトを作成しましょう。メモ帳を起動して以下の二つのプログラムファイルを作成しましょう。HPからカット&ペーストで行った場合、改行コードなどの問題でコンパイルエラーになります。HPでは、文字下げを、タブキー(\t)ではなくスペースを利用して行っているためです。スースファイルを作成したらiappliToolのSampleCav1フォルダの「src」フォルダに保存してください。保存時には、クラス名とファイル名が同じになるようにしてください。同じにしないとコンパイルできません。i-mode
javaの仕様ですので従いましょう。プログラムファイルが作成できたら、プロジェクトの属性のAppName・AppClassの属性に「SampleCav1」と設定します。また、「LastModified」の項目には、年月日を半角スペースで区切って入力します。ビルドを行い、正常に終了したら実行してみましょう。
ソースファイル(SampleCav1.java/SampleCanvas.java)
| SampleCav1.java |
| import com.nttdocomo.ui.*; public class SampleCav1 extends IApplication { //アプリの開始 public void start(){ Display.setCurrent(new SampleCanvas()); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //コンストラクタ public void SampleCanvas(){ } //paintメソッド開始 public void paint(Graphics g){ //データの表示 g.drawString("こんにちわ",0,50); } } |
結果 iappliTool

iアプリの本体は、IApplicationクラスを継承して使用します。そして、IApplicationクラスのstart()メソッドでアプリが開始されます。start()メソッドには、以下の命令が記述されています。
Display.setCurrent(new SampleCanvas());
この命令は、DisplayクラスのsetCurrentメソッドを実行しています。Displayクラスは静的クラスとして定義されていますのでクラス名をそのまま使用します。setCurrentメソッドには、ディスプレイにコンポーネントを設定する働きがあります。引数は、Frameクラスを指定します。Canvasクラスは、Frameクラスを継承しています。そして、SampleCanvasクラスはCanvasクラスを継承しているので指定することが出来ます(多様性)。
setCurrentメソッドを実行した後は、制御がSampleCanvasクラスに移ります。以降、プログラムが終了するまで制御はSampleCanvasクラスが持ったままです。
SampleCanvasクラスには、SampleCanvasメソッドとpaint メソッドが定義されています。SampleCanvasメソッドは、コンストラクタです。実際に、キャンパスに文字を表示しているのはpaint
メソッドです。paint メソッドは、Canvasクラスの象徴メソッドです。オーバーライドして使用します。このメソッドは、キャンパスが表示される時に自動的に実行されます。つまり、i-mode javaが自動的に実行するメソッドなのです。
プログラムの流れとしては、strat→setCurrent→SampleCav1→paintという順番で実行されます。paint メソッドの引数には、(Graphics g)とグラフィッククラスが定義されています。インスタンス名は好きにしてかまいません(Graphics
Graでもかまいません)。ここで、Graphicsクラスは、キャンバスに表示する時に使用するクラスです。paint メソッドの引数のGraphicsクラスは、現在のキャンパスに描画する為のGraphicsクラスのインスタンスをi-mode javaが自動的に生成して渡してくれます。つまり、この引数のGraphicsクラスのインスタンスを利用すれば描画処理が行えます。以下の命令で、キャンバスに文字を表示しています。
g.drawString("こんにちわ",0,50);
drawStringメソッドの引数は、[String,int ,int]と左から「表示する文字列・X座標・Y座標」を指定します。座標に指定する数値はピクセル単位で処理されます。
構文 drawStringメソッド
drawString(String,int ,int)
drawString(表示する文字列・X座標・Y座標)
以上が今回のプログラムの流れです。Graphicsクラスには、どんなメソッドがあるかi-mode javaの「APIリファレンス」で確認してください。
1.3 ライン・四角形・表示色
Graphicsクラスを使用して、キャンパスにラインと四角形を表示します。その時、色を設定することでラインの色や四角形を表示する色を自由に変えることが出来ます。
ソースファイル(SampleCav2.java/SampleCanvas.java)
| SampleCav2.java |
| import com.nttdocomo.ui.*; public class SampleCav2 extends IApplication { //アプリの開始 public void start(){ Display.setCurrent(new SampleCanvas()); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //コンストラクタ public void SampleCanvas(){ } //paintメソッド開始 public void paint(Graphics g){ //色の設定 g.setColor(16777215); g.fillRect(0,0,getWidth(),getHeight());//四角の表示 //色の設定 g.setColor(g.getColorOfName(g.GREEN)); g.drawLine(1,1,1,50);//線の表示 //色の設定 g.setColor(g.getColorOfRGB(48,75,150)); g.fillRect(6,1,20,50);//四角の表示 g.drawRect(30,1,20,50);//四角の枠表示 } } |
結果 iappliTool

描画する色の設定は、setColorメソッドで行います。引数は、色を表すint型の数値です。下では、白の色を指定しています。
g.setColor(16777215);
しかし、これでは一々色の値を調べるのに苦労します。そこで、GraphicsクラスのgetColorOfNameメソッドで値を調べます。getColorOfNameメソッドは、引数に値を指定すると対応するカラーの整数を返します。以下のサンプルでは、緑色のカラーの整数を指定しています。「g.GREEN」は、Graphicsに設定してある色の名前です。この定数を使うことで色の指定が、格段に楽になります。
g.setColor(g.getColorOfName(g.GREEN));
色の整数を調べるには、もう一つ方法があります。GraphicsクラスのgetColorOfRGBメソッドです。引数には、左から赤・緑・青の色合いを指定します。この値は、ペイントソフトの色の作成や色の編集で調べる事が出来ます。
g.setColor(g.getColorOfRGB(48,75,150));
図 ペイントソフトの色の編集ダイアログ

線や四角形を表示しているのは以下のメソッドです。
g.fillRect(0,0,getWidth(),getHeight());//四角の表示
fillRectメソッドで四角形を表示しています。引数には、x座標・y座標・幅・高さを指定します。サンプルでは、getWidth・getHeightメソッドを使用しています。このメソッドは、キャンパスの幅と高さを整数値で返してくれます。
g.drawLine(1,1,1,50);//線の表示
線を表示します。引数は、x開始点・y開始点・x終了点・y終了点となります。
g.drawRect(30,1,20,50); //四角の枠表示
四角形の枠のみを表示します。引数は、fillRectメソッドと同じです。
| メソッド名 | 引数 | 引数のデータ型 | 機能 |
| fillRect(int,int,int,int) | x座標・y座標・幅・高さ | 全てint | 四角を描画 |
| drawLine(int,int,int,int) | x開始点・y開始点・x終了点・y終了点 | 全てint | ラインを描画 |
| drawRect(int,int,int,int) | x座標・y座標・幅・高さ | 全てint | 四角の枠を描画 |
ちょっと補足
文字表示(drawString)のx・y座標と線や図形(fillRect)のx・y座標の働きは少し違います。図形が指定したx・y座標から描画を開始するのに対して、文字のx・y座標は文字の底辺を表します。
図 座標の違い

以下のサンプルは、四角の枠と文字を同じx,y座標で表示しています。
ソースファイル(SampleCav3.java/SampleCanvas.java)
| SampleCav2.java |
| import com.nttdocomo.ui.*; public class SampleCav3 extends IApplication { //アプリの開始 public void start(){ Display.setCurrent(new SampleCanvas()); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //コンストラクタ public void SampleCanvas(){ } //paintメソッド開始 public void paint(Graphics g){ //四角の枠表示 g.setColor(g.getColorOfName(g.GREEN)); g.drawRect(1,30,60,12); //文字の表示 g.setColor(g.getColorOfName(g.BLACK)); g.drawString("こんにちわ",1,30); } } |
結果 iappliTool

結果からも描画位置が違っている事が分かります。描画した四角形など文字列を描画する場合は、この座標の誤差を修正してやら無ければなりません。
1.4 イメージの描画
Graphicsクラスを使用して、キャンパスにイメージを描画します。描画するイメージは、以下のイメージを利用します。ダウンロードして保存してください。プロジェクトを作成したらプロジェクトのresフォルダに保存します。

ソースファイル(SampleCav4.java/SampleCanvas.java)
| SampleCav4.java |
| import com.nttdocomo.ui.*; public class SampleCav4 extends IApplication { //アプリの開始 public void start(){ Display.setCurrent(new SampleCanvas()); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //コンストラクタ public void SampleCanvas(){ } //paintメソッド開始 public void paint(Graphics g){ Image image; MediaImage Mimage; try{ Mimage = MediaManager.getImage("resource:///appli.gif"); Mimage.use(); image = Mimage.getImage(); }catch(Exception e){ System.out.println("例外が発生しました。処理を終了します。"); return; } //イメージの描画 g.setColor(g.getColorOfName(g.GREEN)); g.drawImage(image,1,30); //文字の表示 g.setColor(g.getColorOfName(g.BLACK)); g.drawString("こんにちわ",1,30); } } |
結果 iappliTool

イメージを描画するには、drawImageメソッドを利用します。引数には、イメージクラス・x座標・y座標を指定します。
drawImage(Image,x座標,y座標);
drawImageメソッドの座標の開始点は、イメージの左上になります。文字を表示したのは、座標の開始点の確認の為です。
1.5 キーイベント その一
ゲームでは、ボタンを押してキャラクターを移動させたり、選択肢を選択したりします。今、どのキーが押されたかが分からなければ話になりません。ここでは、Canvasクラスでキーイベントを取得の仕方を説明します。
Canvasクラスには、processEventメソッドというイベントが発生した時に自動的に呼ばれるメソッドがあります。このメソッドをオーバーライドして使用します。
ソースファイル(KeySample1.java/SampleCanvas.java)
| KeySample1.java |
| import com.nttdocomo.ui.*; public class KeySample1 extends IApplication { //アプリの開始 public void start(){ Display.setCurrent(new SampleCanvas()); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //キー番号を格納する変数 private String StrKey; //コンストラクタ public SampleCanvas (){ StrKey = ""; } //描画 public void paint(Graphics g) { //画面を白色で初期化 g.setColor(g.getColorOfName(g.WHITE)); g.fillRect(0,0,getWidth(),getHeight()); //キー番号描画用に表示カラーを赤に変更 g.setColor(g.getColorOfName(g.RED)); //キー番号の表示 g.drawString("押されたKey:"+StrKey,0,50); //キー番号格納変数を初期化 StrKey=""; } public void processEvent(int type, int param){ //キープレスイベント if (type==Display.KEY_PRESSED_EVENT) { //StrKeyに押されたキー番号を格納 StrKey=Integer.toString(param); //再描画処理 repaint(); }//キープレスイベント終了 }//processEventメソッドの終了 } |
結果 iappliTool

プログラムを実行して、エミュレーターのボタンを押すとディスプレイに押されたキーに対するキー番号が表示されます。processEventメソッドには、int type, int paramという二つのパラメーターがあります。この引数は、i-mode
javaの方で渡してくれます。引数typeには、イベントの種類に対応する整数が渡されます。イベントには、キーが押された・キーが離された・リセットなどのイベントがあります。イベントについては、Displayクラスにイベントに対応する定数フィールドが定義されています。
もう一つの引数、paramにはイベントのパラメーターが渡されます。パラメーターは、イベントによって異なります。キープレス・キーアップイベントでは、キーコードが渡されます。
processEventメソッドの中身を確認しましょう。サンプルでは、if文でイベントの種類が格納された引数typeとDisplay.KEY_PRESSED_EVENT(キープレスイベントの定数)の比較を行っています。イベントの種類が、キープレスイベント(type==Display.KEY_PRESSED_EVENT)だとparamの値を参照してStrKeyに代入します。toStringは、Integerクラスの静的メソッドです。引数にint型データを指定すると文字列に変換します。値が代入できたらrepaintメソッドを実行します。repaintメソッドは、paintメソッドを実行するメソッドです。repaintメソッドを使用することで、paintメソッドをプログラムの任意のタイミングで実行する事が出来ます。
paintメソッドの中では、白で画面を初期化してStrKeyに代入されている値を表示します。画面の初期化処理は、白で画面全体を塗りつぶす事で初期化を行います。CanvasクラスのgetWidthメソッドとgetHeightメソッドは、それぞれCanvasクラスの幅と高さを返してくれます。このメソッドの値を塗りつぶす範囲に指定する事で任意の色で画面を塗りつぶしているわけです。
g.setColor(g.getColorOfName(g.WHITE));
g.fillRect(0,0,getWidth(),getHeight());
この命令部分を記述しない場合は、前の処理で描画した文字が残っているのでキーコードが前回の文字に重ねて描画されます。試しに以下のようにコメント化してビルド後、実行してみましょう。
/*
g.setColor(g.getColorOfName(g.WHITE));
g.fillRect(0,0,getWidth(),getHeight());
*/
複数のコードをコメント化する場合は、/*〜*/を利用します。始まりが「/*」でコメントの終了が「*/」です。この記号で囲まれた部分はコメントとみなされてコンパイラがコンパイル時に読み飛ばします。
1.6 キーイベント その二
キーイベントを取得するには、processEventメソッドを使用しました。しかし、ゲームで使用するには、processEventメソッドを使用してrepaintメソッドでpaintメソッドを呼び出して処理するというのは融通にかけます。そこで、もう一つ手法でキーイベントを取得しましょう。このマニュアルでもこの手法を使用してゲームを作成していきます。
ソースファイル(KeySample2.java/SampleCanvas.java)
| KeySample2.java |
| import com.nttdocomo.ui.*; public class KeySample2 extends IApplication { //アプリの開始 public void start(){ SampleCanvas myCanvas=new SampleCanvas(); Display.setCurrent(myCanvas); myCanvas.startApp(); } } |
| SampleCanvas.java |
| import com.nttdocomo.ui.*; public class SampleCanvas extends Canvas{ //キーコードを格納するフィールド private String StrKey; //描画用のGraphicsクラス private Graphics g; //コンストラクタ public SampleCanvas (){ StrKey = ""; } //描画 public void paint(Graphics pintg) {} //プログラムの開始 public void startApp (){ //Graphicsクラスを格納 g= this.getGraphics(); while(true){ //キー番号の取得 StrKey =Integer.toString(gKey()); //画面の初期化 g.setColor(g.getColorOfName(g.WHITE)); g.fillRect(0,0,getWidth(),getHeight()); //キー番号の描画 g.setColor(g.getColorOfName(g.RED)); g.drawString("押されたKey:"+StrKey,0,50); } } public int gKey(){ int a; while(true){ //スリープ処理 //最初のスリープ処理ボタンを連続して押された時、 //メッセージがすぐ消えてしまう事を防止。 try { Thread.sleep(200); } catch (Exception e) {} //キーが押されていない状態 0ならループの先頭に戻る if((a=this.getKeypadState())==0) continue; //キーが押されたら押されたキーコードを求める for(int i=0;i<=22;i++){ if(( 1<<i & a)!=0){ return i; } } } } } |
結果 iappliTool

プログラムを実行して、エミュレーターのボタンを押すとディスプレイに押されたキーに対するキー番号が表示されます。プログラムの説明をしましょう。i-mode
javaの自動イベントを利用するとどうしても制約が生まれます。プログラムの流れをi-mode
javaの自動イベントではなく、プログラム作成側で制御した方がこちらが望む処理が記述できるのです。
そこで、startAppメソッドに無限ループを意図的に作成することでプログラム終了まで制御をstartAppメソッドに移すことが出来ます。startAppメソッドの処理の流れを説明しましょう。
g= this.getGraphics();
thisは、プログラムが使用されているクラスを表します。startAppメソッドはKeySample2にありますので「KeySample2クラス」を表します。getGraphicsメソッドは、Canvasクラスのメソッドです。キャンバスに描画するためのグラフィクスオブジェクトを取得します。KeySample2クラスは、Canvasクラスを継承しているので使用できます。getGraphicsメソッドは、戻り値にGraphicsクラスを持ちます。この戻り値のインスタンスは、キャンパスに描画するためのGraphicsクラスです。paintメソッドの引数と同じ働きをします。
キーイベントを取得しているのは、gKey()メソッドです。押されたキー番号を戻り値で返します。gKey()メソッドでも無限ループを使用します。ボタンが押されるまでこのメソッドから制御が抜けることが無いようにするためです。最初にスリープ処理を行っています。
try {
Thread.sleep(200);
} catch (Exception e) {}
プログラムで、無限ループを使用すると一秒間にUPCが処理できるだけループが実行されてしまいます。そこで、Threadクラスのsleepメソッドを使用して待機処理を行います。引数に指定した整数値のミリ秒分待機しますが、機種の能力により異なります。
if((a=this.getKeypadState())==0) continue;
キーを取得するには、CanvasクラスのgetKeypadStateメソッドを使用します。戻り値が0の場合は、何も押されていないということです。また、制御文の判定処理に変数aに戻り値を代入する命令を使用しています。変数aにgetKeypadStateメソッドの戻り値を代入して、変数aの値が0かどうか判定しているのです。0ならば何も押されていないので、continueで繰り返し処理の先頭に処理を移します。もし、キーが押されたら次の処理に制御が移ります。
for(int i=0;i<=22;i++){
if(( 1<<i & a)!=0){
return i;
}
}
この繰り返し処理は、キーが押されていた時の処理です。この命令は、説明が必要でしょう。まず、以下にキーコードを表すDisplayクラスの静的定数フィールドの一覧を示します。APIリファレンスには、16進表現で記載されています。(先頭の「0x」は、16進表現のと言う意味です)。
| データ型 | 定数と格納データ(16進表現) | 十進表現 |
| int | KEY_0 数字キー0 (=0x00)。 |
0 |
int |
KEY_1 数字キー1 (=0x01)。 |
1 |
int |
KEY_2 数字キー2 (=0x02)。 |
2 |
int |
KEY_3 数字キー3 (=0x03)。 |
3 |
| int | KEY_4 数字キー4 (=0x04)。 |
4 |
| int | KEY_5 数字キー5 (=0x05)。 |
5 |
| int | KEY_6 数字キー6 (=0x06)。 |
6 |
| int | KEY_7 数字キー7 (=0x07)。 |
7 |
| int | KEY_8 数字キー8 (=0x08)。 |
8 |
| int | KEY_9 数字キー9 (=0x09)。 |
9 |
| int | KEY_ASTERISK (*)アスタリスクキー (=0x0a)。 |
10 |
| int | KEY_POUND (#)パウンドキー (=0x0b)。 |
11 |
| int | KEY_LEFT 左方向キー (=0x10)。 |
16 |
| int | KEY_UP 上方向キー (=0x11)。 |
17 |
| int | KEY_RIGHT 右方向キー (=0x12)。 |
18 |
| int | KEY_DOWN 下方向キー (=0x13)。 |
18 |
| int | KEY_SELECT 選択/決定キー (=0x14)。 |
20 |
| int | KEY_SOFT1 ソフトキー1 (=0x15)。 |
21 |
| int | KEY_SOFT2 ソフトキー2 (=0x16)。 |
22 |
アプリの操作で必要になるのは、数値キーと方向キー、あとソフトキーになるでしょう。これらのキーは、0から22の範囲に収まっています。for文の処理を0〜22まで繰り返しているのは、これらのキーを一つずつ突き合わせるためです。一番、理解しがたいのはfor文の中のキーコードの判別処理でしょう。
if(( 1<<i & a)!=0){
return i;
}
「1を、for文のインデックス分左にシフト(1<<i )して、その結果を「& a」で論理演算しています。ややこしいですね。論理演算に使用している変数aには、getKeypadStateメソッドで取得した押されたキーの値が入っています。値の内容は、キーコードではありません。getKeypadStateメソッドは、押されたキーに対応するビットを1にした値を返します。
基礎編で勉強したように、コンピュータの最小データはON/OFFのビットです。intデータもビットの塊です。intデータのサイズ分、ビットが並んでいると考えてよいでしょう。intもビットを利用して数値を表現しているのです。以下のような感じです。
intの表現
intの0:上位省略・・・00000000000000
intの1:上位省略・・・00000000000001
注意 上記は数値を表示する文字が多数になるため上位のビットは削ってあります。
getKeypadStateメソッドの戻り値は、2が押された場合は2番目のビットを1にして返します。もし、10が押された場合は10番目のビットを1にして返します。押されたキーとgetKeypadStateメソッドの戻り値の例を以下に示します。
例 getKeypadStateメソッドの戻り値

直接、キーコードを返してくれると楽な感じがします。コンピュータは、ON/OFFのデータしか扱えません。その特徴からこの様なビットを利用した処理が非常に得意なのです。ビットをずらして、あるビットを1にすればよいだけなのです。コンピュータ的には、楽な処理なんですね。
では、処理の説明に戻りましょう。変数aには、以上のような値が入っています。2が押され場合を元に、処理の流れを数値の変化で追って見ましょう。「2」が押された場合、変数aに格納されるビット表現は「上位省略・・・00100」になります。0起算ですから3番目のビットが1になります。
最初のループ処理を行います。for文のインデックスiの値は0です。変数iが0ですから「1<<i 」は、「1<<0」という計算を行います。「1」は、自動的にintの1として扱われます。1のビット表現は以下のようになります。
intデータ 1のビット表現
上位省略・・・00000000000001
「1<<0」ですから、1を0ビット分左にシフトします。結果は、「上位省略・・・00001」となります。最初のままですね。この計算結果と、変数aの値を「&」で論理演算処理を行います。この処理で利用する「&」は、true・falseに利用する論理演算子ではありません。数値データのビット単位の論理演算を行う論理演算子です。この「&」は、ビット単位の論理積を求めます。左辺と右辺のデータをビット単位で比較します。論理積ですから両方のビットが「1」の場合のみビットを1にして、それ以外ならビットは0となります。「1<<0」のビット表現と演算結果を図にすると以下のようになります。両方、「1」のビットが無いので結果はオール0です。
図 「1<<0」のビット表現と演算結果

intデータのビットがオール0ですので、値は0となります。つまり、「( 1<<i & a)」の結果が0です。if文では、「if(( 1<<i & a)!=0)」と演算結果を0と比較しています。「!=」ですから「0でなければ」ということです。if文の条件判定は、falseとなりループを継続します。
2回目のループでは、for文のインデックスiの値は1です。変数iが1ですから「1<<i 」は、「1<<1」という計算を行います。「1<<1」ですから、1を1ビット分左にシフトします。シフトして出来た空白のビットは0で埋められますから、結果は「上位省略・・・00010」となります。この計算結果と、変数aの値を「&」で論理演算処理を行います。「1<<1」のビット表現と演算結果を図にすると以下のようになります。
図 「1<<1」のビット表現と演算結果

変数iが1の場合も演算結果は、0になりますからif文の条件は満たしません。ループの処理を継続します。
3回目のループでは、、for文のインデックスiの値は2です。変数iが2ですから「1<<i 」は、「1<<2」という計算を行います。「1<<2」ですから、1を2ビット分左にシフトします。シフトして出来た空白のビットは0で埋められますから、結果は「上位省略・・・00100」となります。この計算結果と、変数aの値を「&」で論理演算処理を行います。「1<<2」のビット表現と演算結果を図にすると以下のようになります。
図 「1<<2」のビット表現と演算結果
![]()
「1<<2」の演算結果も変数aの値も3ビット目が1です。演算結果は、「上位省略・・・00100」で整数の「8」が求められます。「( 1<<i & a)」の結果が8です。if文の条件である「(( 1<<i & a)!=0」が満たされます。後は、if文のブロック内の処理を行って終わりです。
if文のブロック内では、「return」に変数iを指定しています。変数iは、for文のインデックスです。ビットの位置を格納していましたね。キー押下の値は、押されたキーのビットを1にした値です。変数iを返す事で押されたキーコードを返す事になります。
少しややこしかったでしょうか?。getKeypadStateメソッドの戻り値がキーコードではない為、戻り値をキーコードに変換する作業が生じた訳です。順を追って考えれば難しくは無いと思いますが・・・。
どうしても理解できないと言う方は、gKeyメソッドをそのまま利用すれば問題はありません。gKeyメソッドがキーコードを返してくれると覚えておけば良いでしょう。スリープ処理を変えたければ、sleepメソッドの中身を替えれば良いのです。また、拡張APIのキーコードも取りたければfor文の回数を拡張APIの値まで増やせば良いのです。細かいカスタマイズを望む場合は、辛いですが値の移り変わりを考えて処理を理解してください。
今回のプログラムでは、0ボタンと2ボタンが同時に押された場合を考慮していません。同時に押された場合も押されたキーに対応するビットが1になります。同時押しの場合は、複数の1が存在する事になります。
ボタンの同時押しの戻り値
上位省略・・・00000000000101
補足 描画の単位
文字やキャンパスの描画には、ピクセルと言う単位を利用します。画面は、細かいマスの集まりです。そのマスに色を表示させて色々なイメージや文字を描画します。130×130の画面は、横に130マス、縦に130マスで構成されます。この画面を構成するマスの最小単位がピクセルと考えてください。座標もピクセル単位です。例えば、x座標が+30の場合、画面の開始位置より+30ピクセル離れた位置となります。