はじめに:
モバイルゲームの2人対戦の実現方法には、いくつかあります。例えば:
- オンライン対戦(クライアントのリクエストを転送するサーバーが必要。各種大型モバイルゲームの手法)
- 画面分割対戦(スマートフォンの画面を上下に分割。典型的な例は『フルーツ忍者』の2人対戦)
- Bluetooth対戦(Bluetoothを通じて接続。典型的な例は『三国Kill』のオンライン版)
まず、オンライン対戦は検討外です(コストが高く、サーバー代もかかるため...)。一方、画面分割対戦は制約が大きすぎます(2人で1台のスマホを使うのは非常に不便です)。
そのため、Bluetooth対戦は良い選択肢です。低コストで実現可能です(『三国Kill』が良い例で、少なくとも実現可能であることは証明されています)。
1. リソース収集
「Android 開発 Bluetooth 接続」で検索し、多くの有用な情報を見つけました。選別した結果、情報の多くが BluetoothChat に関連するものであることがわかりました。調べてみると BluetoothChat は公式Demoであることがわかったので、話が早いです。
まずソースコードをダウンロードし、ついでに先人によるソースコード解析も見つけたので、かなり手間が省けました。簡単に整理したリソースは以下の通りです(最初の2つはネットからの借用、後ろの2つは作成したばかりのものです):
2. Demoのテスト
Demoを入手したら、まず動作を確認します:
- Eclipseにインポートすると赤いエラーマークが出ましたが、AndroidManifest.xmlのSDKバージョンを修正したところ、エラーは消えました。
- スマホを接続してインストール・実行したところ、アプリが異常終了しました。ログを確認すると、エラーメッセージは「you can not combine custom titles with other title」でした。
- 最終的にリソースファイルを変更することでこの問題を解決しました。問題の詳細と解決策は以下の通りです:
- テストに成功し、実機でのチャットも問題ありませんでした。
Demoの使用中に遭遇する可能性のある問題:
- you can not combine custom titles with other title のエラー原因と解決策は?
解決策:XML内の該当するActivityのテーマを @android:style/Theme に変更する。
注意:XMLのActivityに theme タグがない場合は、タグを追加して上記の値を設定してください。
実機での実行結果は以下の通りです:
3. Bluetooth接続プロセス
- Bluetooth関連の権限を宣言する(権限の詳細については先人のソースコード解析を参照してください。ここでは割愛します)。
- 自端末のBluetoothアダプタを取得する(BluetoothAdapterはシステムが提供するBluetoothインターフェースであり、このアダプタを通じて端末のBluetoothを操作します)。
- 接続可能な外部Bluetoothデバイスをスキャンする(Bluetoothモジュールから返されるブロードキャストメッセージを受信することで、外部デバイスの関連情報を取得します)。
- 外部デバイスのMACアドレスを取得する。
- MACアドレスを通じてSocket接続を確立する(Socket接続ができれば、あとは一般的なSocketチャットプログラムと大きな違いはありません)。
- Socket接続を通じてメッセージを送受信する。
簡単に言えば、接続プロセスは上記の数ステップです。筆者がソースコードを理解・分析した上で(先人の解析も参照)、より読みやすい注釈を追記しました。例:
4. まとめ
ソースコードの分析は時間と労力がかかる作業ですが、時間があるなら、その努力は間違いなく報われます。単なるコピー&修正(copy-modify)よりもはるかに優れています。他人のコードを分析する過程で、以下のものを得ることができます:
- 実現原理(例えば、機能を実現するための各コンポーネントの役割分担や相互作用など。単にコードブロックの機能を理解するだけではありません)
- コーディング規約(例えば、���初はなぜメソッドを分けたり、クラスを分けたり、レイヤーを分けたりするのか疑問に思うでしょう...)
- コーディングスタイル(変数、メソッド、クラス、パッケージの命名規則、インデントのスタイルなど...)
- ちょっとしたテクニック/常識(例えば、リリース前にデバッグ情報を削除する手間を省くために、デバッグ中であることを示すフラグ変数を定義し、デバッグ情報を出力するすべてのコードを if ブロックで囲みます。リリース前にはフラグ変数を false に変えるだけで済みます)

コメントはまだありません