Mobile:NEWS 2003年11月7日 00:33 AM 更新

BREW プログラミング入門(3)
画面に描画をしてみよう(3/3)


前のページ

図形を動かしてみよう

 図形を描けるようになったら、今度は図形に動きをつけてみましょう。ここでは、図形を動かすサンプルとしてShapeアプレットを作成してみます。

 今回はユーザーのキー入力により動かすのではなく、時間とともに自動的に変化するような動きをつけてみます。このような処理にはタイマーを使うとよいでしょう。

 BREWは、一定時間が過ぎたときに通知してくれるタイマーを備えています。タイマーの設定はISHELL_SetTimer()関数により行います。

 「BREW APIリファレンス」で調べますと、次のような関数であることが分かります。

int ISHELL_SetTimer ( IShell * pIShell, // IShell オブジェクト int32 dwMSecs, // タイマーで通知してもらう時間をミリ秒で指定 PFNNOTIFY pfn, // 通知を受け取る関数 (コールバック関数) void * pUser // ユーザー データ )

 PFNNOTIFYについても調べてみますと、通知を受け取る関数は次のようなプロトタイプを持つ必要があることが分かります。

void TimerCallback(void * pData)

 これを使えば図形に動きをつけられそうです。

 でもちょっとまってください。ここで重要な問題が出てきます。タイマーで通知されるたびに図形を動かすとして、その図形の座標はどこに記憶しておけばよいのでしょうか。

 BREWには、いままで述べてこなかった重要な制限事項があります。「BREWではグローバル変数は使えない」のです。また、C言語の静的変数 (static変数) も使うことはできません。これはBREWというシステムの構造に根ざす、避けられない制限です。

BREWプログラミングにC++を使う場合、静的メンバ変数を使うこともできません。

独自のアプレット構造体

 ではどうやってグローバルなデータを記憶したらよいのでしょう。

 BREWでは、グローバルなデータはアプレット構造体に格納することになっています。これまでアプレット構造体としてAEEAppletしか使用してきませんでしたが、アプレット構造体は開発者が任意に定義できるのです。

 今回作成する図形移動アプレットでは、次のようにアプレット構造体を定義します。

// 独自のアプレット構造体 typedef struct { AEEApplet a; // 先頭のメンバは必ず AEEApplet 型とすること。

int x0, y0, r0; // 図形0の中心と半径 int x1, y1, r1; // 図形1の中心と半径 int x2, y2, r2; // 図形2の中心と半径 } ShapeApplet;

 このように、「アプレット構造体の先頭のメンバは必ずAEEApplet型にしないといけません」。この条件さえ満たしていれば、あとは自由にメンバ変数を加えることができます。

 独自にアプレット構造体を定義した場合は、AEEClsCreateInstance()関数の実装を少し変更しなければなりません。

 まず、アプレット構造体を作成する AEEClsCreateInstance()関数で、AEEApplet_New()関数を呼び出すとき、独自アプレット構造体のサイズを指定する必要があります。アプレット構造体に必要なメモリを確保する必要があるからです。

 また通常は、AEEApplet_New()を呼び出した後で、アプレット構造体の初期化を行うことになるでしょう。


// // このBREWモジュールでサポートされている // BREWアプレットを作成する関数です。 // int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,void ** ppObj) { *ppObj = NULL; if (ClsId == AEECLSID_SHAPE) { if (AEEApplet_New(sizeof(ShapeApplet), ClsId, pIShell, po, (IApplet**)ppObj, (AEEHANDLER)Shape_HandleEvent, NULL) == TRUE) {

// アプレット構造体の初期化を行う ShapeApplet* app = *ppObj;

app->x0 = 20 + RandInt(60); app->y0 = 20 + RandInt(60); app->x1 = 20 + RandInt(60); app->y1 = 20 + RandInt(60); app->x2 = 20 + RandInt(60); app->y2 = 20 + RandInt(60); app->r0 = 4 + RandInt(10); app->r1 = 4 + RandInt(10); app->r2 = 4 + RandInt(10);

return (AEE_SUCCESS); } } return (EFAILED); }

このコードのRandInt()は乱数を返す関数で、独自に定義した関数です。詳細はソースコードをダウンロードして確認してください。

 このように、独自のアプレット構造体を定義すれば、イベント ハンドラに渡されるIApplet*引数はShapeApplet*に変換できます。

// // Shapeアプレットのイベント ハンドラ // static boolean Shape_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam) { switch (eCode) { case EVT_APP_START: Shape_OnAppStart((ShapeApplet*) pi); return TRUE; case EVT_APP_STOP: return TRUE; default: break; } return FALSE; }

 それでは、Shapeアプレットの残りのコードを示すことで、ソースコードを完成させましょう。

// // Shapeアプリが起動すると呼び出されます。 // static void Shape_OnAppStart(ShapeApplet* app) { // 描画とタイマー設定を行う Shape_OnTimer(app); }

// // タイマーで呼び出される関数 // static void Shape_OnTimer(ShapeApplet* app) { IGraphics* graphic;

// 図形を動かす app->x0 += RandInt(3) - 1; app->y0 += RandInt(3) - 1; app->x1 += RandInt(3) - 1; app->y1 += RandInt(3) - 1; app->x2 += RandInt(3) - 1; app->y2 += RandInt(3) - 1;

app->r0 = ABS(app->r0 + RandInt(3) - 1); app->r1 = ABS(app->r1 + RandInt(3) - 1); app->r2 = ABS(app->r2 + RandInt(3) - 1);

// IGraphics オブジェクトの取得 ISHELL_CreateInstance(app->a.m_pIShell, AEECLSID_GRAPHICS, &graphic);

// 描画を行う Shape_OnDraw(app, graphic);

// IGraphics オブジェクトの解放 IGRAPHICS_Release(graphic);

// 再度タイマーを設定 (100ミリ秒後) ISHELL_SetTimer(app->a.m_pIShell, 100, Shape_OnTimer, app); }

// // 描画ルーチン // static void Shape_OnDraw(ShapeApplet* app, IGraphics* graphic) { AEECircle c0, c1, c2; AEETriangle tri;

// 背景を白でクリア IGRAPHICS_SetBackground(graphic, 255, 255, 255); IGRAPHICS_ClearViewport(graphic);

// 三角形の描画 tri.x0 = app->x0; tri.y0 = app->y0; tri.x1 = app->x1; tri.y1 = app->y1; tri.x2 = app->x2; tri.y2 = app->y2;

IGRAPHICS_SetFillMode(graphic, FALSE); IGRAPHICS_SetColor(graphic, 0, 0, 0, 0); IGRAPHICS_DrawTriangle(graphic, &tri);

// 円の描画 c0.cx = app->x0; c0.cy = app->y0; c0.r = app->r0;

c1.cx = app->x1; c1.cy = app->y1; c1.r = app->r1;

c2.cx = app->x2; c2.cy = app->y2; c2.r = app->r2;

IGRAPHICS_SetFillMode(graphic, TRUE); IGRAPHICS_SetFillColor(graphic, 255, 0, 0, 0); IGRAPHICS_DrawCircle(graphic, &c0);

IGRAPHICS_SetFillColor(graphic, 0, 255, 0, 0); IGRAPHICS_DrawCircle(graphic, &c1);

IGRAPHICS_SetFillColor(graphic, 0, 0, 255, 0); IGRAPHICS_DrawCircle(graphic, &c2);

// 画面ビットマップへの描画を実際に表示する IGRAPHICS_Update(graphic); }

※今回の記事のソースコードは、ソフィア・クレイドル のサイトからダウンロードできます。

著者紹介
倉谷智尋:ソフィア・クレイドル研究開発部チーフサイエンティスト。ソフィア・クレイドルは、2002年2月京都市にて、無限の可能性を秘めたソフトウェア職人たちが楽しく集い、自ずと自己実現が達成される場になることを目指して創業。在籍スタッフの平均年齢は20代前半と若いが、その大半がプログラミング歴10年以上とそのプロフェッショナリティは極めて濃い集団である。

 これまでにBREW用アプリケーションフレームワークケータイJavaプログラム圧縮技術ケータイJavaブラウザ技術、ケータイメッセンジャー技術などを総合的に研究開発し、「高品質な共通プラットフォーム」の実現を目指してきた。

ご感想、ご質問はこちら(zdnet-contact@s-cradle.com)まで。



関連記事
▼ BREW プログラミング入門(1):BREW SDKをインストールしよう
本連載は、BREWに興味がありプログラミングを始めてみたいけれど、どこから手をつけてよいか分からない方々を対象に、ステップ・バイ・ステップでBREWプログラミングを行う方法を解説していきます。

▼ BREW プログラミング入門(2):“HelloWorld”プログラムを作ろう
前回の連載では、BREW SDK 2.1をインストールするところまで解説しました。今回は実際にソースコードを書き、BREWエミュレータで動かしてみましょう。画面に "Hello World" と表示する簡単なBREWアプリを作成します。

▼ Qualcomm、携帯電話向けプラットフォーム「BREW」発表──au端末に搭載
▼ “携帯電話のOS”を目指すBREW──国内でも1号機
▼ BREWとは何か?──Javaとの違い

[倉谷智尋, ITmedia]

Copyright © ITmedia, Inc. All Rights Reserved.

前のページ | 3/3 | 最初のページ



モバイルショップ

最新CPU搭載パソコンはドスパラで!!
第3世代インテルCoreプロセッサー搭載PC ドスパラはスピード出荷でお届けします!!

最新スペック搭載ゲームパソコン
高性能でゲームが快適なのは
ドスパラゲームパソコンガレリア!