「ソフトウェア」カテゴリーアーカイブ

Moai SDK でゲームを作ろう(Android でサンプルを動作させる)

開発用の Linux 上でプログラムが動作したので、次は Android でプログラムを実行しようと思う。

で、調べながらやってみた結果、下記ページの説明通りにすることで、 Android でサンプルが動作した。
http://www.gamefromscratch.com/post/2012/08/28/Setting-up-a-Moai-Android-host-build-environment.aspx

Screenshot_2014-01-01-00-28-42

いい感じですな!
Android の実機で作ったプログラムが動作するのが確認できたので、簡単でよいのでゲームっぽいものを作ろうと思う。

Moai SDK でゲームを作ろう(Linux 上でサンプルを動作させる)

Moai SDK はホスト環境でも動くようなので、まずは Linux(Ubuntu) で動作させようと思う。

下記のリンクに手順が書いてあるけど、要は普通にビルドすれば良いらしい。
http://franciscotufro.com/2013/01/compiling-moai-on-linux/

私の場合、以下のコマンドでビルドできた。

apt-get install libxmu-dev
git clone git://github.com/moai/moai-dev.git
cd moai-dev/
git checkout linux
cd cmake
cmake .
make

そして、動作確認としてサンプルの anim-basic を動作させた。

cd moai-dev/samples/anim/anim-basic
../../../cmake/moai/moai main.lua

moai_2013_1231_anim-basic

サンプルの実行方法は、実行したいサンプルのディレクトリに移動して、moai の実行バイナリに main.lua を渡せばよい。

次は Android の実機でサンプルが動作するのを目指したい。

Moai SDK でゲームを作ろう (調査してみてわかったこと)

Android 向けのゲームを作るにあたり、いろいろ調べた結果 Moai SDK っていうのが良さそうに思った。

  • Android, iOS, Chrome 用の 2D ゲーム向けのフレームワーク
  • C++ でクラス作って Lua で操作するような作りになっている
  • オープンソース(ライセンスはゆるめの CPAL)

で、Kindle で Moai SDK の書籍(英語)も買って読んで「いいなー♪」とか思っていたが…、もう少し調べたいたところ大変なことがわかった。

「Moai SDK っていうプロジェクトは、もう息してない…」

下記のリンク先が詳しい内容だけど、要約するとメインの開発者が「もうええわ!」って感じで更新しない宣言をしたらしい。確かに github 上のソースも数ヶ月くらい更新ないし…。

http://getmoai.com/forums/thoughts-on-the-future-of-moai-sdk-t2012/

ただ、使うにあたっては起動ロゴに2秒以上 Moai SDK のロゴを表示するか、クレジットに表示するか、っていう要求のゆるさが気に入っているし、何より自分でフレームワークを作るよりは良いだろう、という判断のもとに Moai SDK を使ってゲームを作ってみようと思う。

次回は、実際に Moai SDK をセットアップして Linux 上や Android 上で画像でも表示するプログラムを作ってみたい。めげずに頑張る!

記録済みデータのフォーマットを Ruby で変更する

あるツールを使ってデータを記録したが、ツールに手を加えたためにデータの互換性がなくなってしまったのを「互換性がないなら、スクリプトで変更すればいいじゃない」という作業の流れを書きだしたものが、この記事です。

どういう仕組みで何を記録したのか

LMS511 という平面の距離を計測できるセンサがあるのですが、そのセンサとの通信内容を全て記録しました。通信データの記録は LMS11 から距離データを取得するために C++ で実装した Lms_driver というクラスで行なっています。

この Lms_driver クラスは Connection インターフェースを継承させていて、Connection インターフェースはセンサに対する open, read, write を提供します。そのため、Connection インターフェースの中身を差し替えることで、センサからのデータ取得、センサからデータを取得しつつログを記録、ログからデータを読み出して再生、ということが実現できます。

lms_driver_usage_2013_1228

ただ、この仕組みでデータの記録と再生を実現しようとすると Lms_driver でセンサとの通信に使っているコマンドの順番を変えると記録済みのデータが再生できなくなる、という欠点があります。今回は、いろいろ機能を追加すべく Lms_driver を変更した結果、過去に記録したデータが再生できなくなってしまいました。

行う必要があること

過去の実装から変更した点は、センサに発行するコマンドを追加した程度なので、そのセンサからの応答を過去のデータに追加してしまえば O.K. です。

実際に行ったこと

LMS511 との通信は STX, ETX が付加された以外は普通の ASCII 文字列で行われるため、Ruby スクリプトを用いて必要な箇所を置換していくことにします。

具体的に行う処理は

  • 追加したコマンドぶんの応答を追加
  • データ取得コマンドの変更による、データ先頭のコマンド文字列の置換

くらいかな。
改めて書きだしてみると、大したことはないですね。作成するスクリプトの方針としては、引数で与えたファイルの内容を読み込んで、置換でどうにかすることにします。

まず、引数で与えたファイル名を読み出すあたりまでの実装は、こんな感じでしょうか?

# -*- coding: utf-8 -*-
# LMS のログデータを変換するスクリプト

# 引数で渡されたファイルを順に処理する
ARGV.each { |log_file|
  original = File.open(log_file).read

  # コマンドの応答を追加する
  # !!!

  # 必要な置換を行う
  # !!!
}

次に、置換まわりのコードを追加します。(コードの一部の通信データを省略しています)

# -*- coding: utf-8 -*-
# LMS のログデータを変換するスクリプト

# 引数で渡されたファイルを順に処理する
ARGV.each { |log_file|
  converted = File.open(log_file).read

  # 最初のコマンド応答の部分を切り取る
  converted.sub!(/.+?/, "")

  # 必要な置換を行う
  converted.gsub!(/sRA/, "sSN")

  # 最初のコマンド応答を追加する
  converted = "sRA (省略) sEA LMDscandata 1" + converted

  # ファイル名を変更して出力する
  output_file = "converted_" + log_file
  File.open(output_file, "w").write(converted)
}

いつものことですが、実際に手を動かしてみると簡単です。
個人的には、面倒くさがらずに簡単ならもう少し早く取りかかれるようになりたいのですが「怠惰」はプログラマにとって美徳なので悩ましいところです。

まとめ

これからは怠惰な気持ちで楽することを考えつつも、実際には怠惰にならないようにする。

SDL で Android ゲームの開発 (画像が表示できた)

下記サイトを参考にした結果、Android タブレットに画像を表示させることができた。
http://www.dinomage.com/2013/01/howto-sdl-on-android/

このサイトと SDL リポジトリの SDL/README-android.txt に、ここまでの手順が書いてある。でプログラムを実行して Android タブレット(Nexus 7) で表示したところ、

Screenshot_2013-12-22-22-53-59

色が変だ…。
悩みつつ調べてみた結果、Gimp で png を bmp に変換するときに 24 bit を指定することで適切な色になった。

Screenshot_2013-12-23-01-48-20

gimp_bmp_setting_2013_1223

色についての詳しいことは、後でいいので調べて理解したい。

ここまでのソースコードは、下記プロジェクトで管理中。
https://bitbucket.org/satofumi/zunda_farm/src/67b09f285031/example/draw_image/?at=default

「赤城さんのお風呂タイマー」用のテーマを作ってみよう!

「赤城さんのお風呂タイマー」のテーマとは

「赤城さんのお風呂タイマー」用のテーマの作成方法の紹介です。テーマとはツールにキャラクター等の画像を配置する仕組みで、このツール専用の「伺か」のようなものです。

zunko_setup_screenshot

 

テーマを作ってみる

  1. まず、これがテーマを作るために今回用意したサンプルファイルです: sample_theme
  2. このファイルを展開したフォルダを bath_timer-0.1.6\theme\ に配置します。
  3. bath_timer-0.1.6\theme\sample_theme\build.bat を実行します。
  4. bath_timer-0.1.6\theme\sample_theme.dat ができていれば成功です。
  5. ツールを起動し直すとテーマ一覧に Sample Theme が追加されます。

sample_theme_list

テーマを構成するファイルと役割

ここまででテーマが作成できました。 次は、このテーマを変更できるようにするために、構成するファイルの内容を説明します。

?README.txt
「テーマについて」 の前半に表示されるメッセージです。

COPYING.txt
「テーマについて」 の後半に表示されるメッセージです。

logo.pngテーマ一覧に表示される画像です。

resource.yaml
アニメーションなどの定義を行っている YAML ファイルです。
Image: Background … テーマの最も後ろに表示される画像のファイル名です。
Image: Parts … 表示する画像のファイル名と表示位置を定義しています。Cell: … アニメーションのセルに相当します。重ねて表示する画像を定義します。
Pattern: … セルと表示ミリ秒の組み合わせでアニメーションを定義します。

events.lua
ツールが操作されたときに呼び出される関数が記述された Lua スクリプトです。
例えば、ツールがクリックされたときの処理は
function single_clicked(theme)
theme:set_pattern(“normal”)
end
となっており、normal のアニメーションの開始を指示しています。

最後に

ちゃんとしたテーマエディタを作ろうとしたのですが、紹介だけになってしまいました…。
わからないことや希望があればコメントを下さい。なんとかします。

SICK LMS5xx 用の C++ ドライバの作成 (マルチエコーを扱えるようにした)

LMS511 用に開発している C++ ドライバの Lms_driver で、マルチエコー情報を扱うあたりを実装した。

lms_viewer_2013_1217
2エコー目の距離が水色で表示されている

とりあえずは利用できるようになったので、ここまでの実装を hrk_lidar という名前のライブラリとして公開した。URG や LMS センサ用の C++ ドライバで Windows, Linux, Mac で動作する。

hrk_lidar, Lidar_viewer パッケージのダウンロードページ
https://bitbucket.org/satofumi/hobby_robot_sdk/downloads

ドライバの細かな修正は、使いながら行っていきたい。
あとは、このドライバで利用している Viewer も Lidar_viewer という名前のパッケージにして公開した。(Windows 版 binary は Lidar_viewer_win? という名前)

今後は、前回の実験で取得したデータを解析するあたりを行いたい。

Android 開発環境の構築 (Linux)

Android 環境を Linux に構築した。構築方法は本家サイトを見れば十分だった。

Android NDK の hello-jni をサンプルが無事に動作した。

Screenshot_2013-12-14-20-22-36
Nexus 7 で動作させたときのスクリーンショット

開発環境が構築できたので、次は Android デバイスに画像を表示するあたりのサンプルを作ろうと思う。

「赤城さんのお風呂タイマー」の仕組み

赤城さんのお風呂タイマーとは

「赤城さんのお風呂タイマー」は「艦隊コレクション -艦これ-」用のタイマーツールです。タイマーの値をこのツールから確認できるため、ゲーム時にタイマーの値を見に行く手間を減らすことができます。「赤城さんのお風呂タイマー」では、タイマー値の取り込みをキャプチャした画像の OCR で行なっています。

処理の概要

赤城さんのお風呂タイマーでの処理の概要は、以下のような流れになります。

    1. ユーザがキャプチャボタンを押したら処理を開始する。
    2. ゲーム画面位置を検出する。
    3. タイマー値の OCR 処理を行う。
    4. 取り込んだタイマー値をファイルに保存し表示に反映させる。

empty_capture wind_0_90 value_captured

詳しい処理は、以降で順に説明していきます。

ゲーム画面位置の検出

キャプチャボタンが押されたときに画面のスクリーンショットを GUI ライブラリの Qt の機能で取得し、その画像内からゲーム画面の位置推定を行います。

具体的には、あらかじめゲーム画面とマッチする画像を用意しておき、画像処理ライブラリの OpenCV のテンプレートマッチングでゲーム画面の位置を推定しています。マッチングに用いる画像はゲーム画面の拡大率が 100 % 用のものと、100 % 以外用の 2種類あります。

ゲーム画面の拡大率が 100 % のときの処理

ゲーム画面と同じ大きさの画像を用意し、OpenCV の matchTemplate() を用いてマッチングを行なっています。マッチング用の画像はツールの data フォルダにあり、何かあった場合にユーザでも変更できるようになっています。

frame
テンプレート画像
frame_100_matched
マッチング結果を赤色で表示

それなりに良い精度で認識してくれます。ありがとう OpenCV !

ゲーム画面の拡大率が 100 % 以外のときの処理

この処理は 100 % 用の画像でのマッチングに失敗した場合に行われます。処理の概要としては4すみ用に L 字型のマッチング画像を用意しておいてマッチングさせ、結果として、ゲーム画像の1辺が推定できればその大きさをゲーム画像として処理します。

frame_success
揃っている辺があれば認識できたとみなす
frame_fail
揃っている辺がなければ認識失敗とみなす
推定した位置の扱い

ここで推定したゲーム画面の位置は、以降のタイマー値の読み込みに成功した場合にキャッシュされます。つまり、タイマー値が適切に読み込めた場合は、次回のキャプチャ時にはこれらのテンプレートマッチングの処理は省略されます。
デバッグ動作時に出力される profile_log.txt によると、この推定には 300 ms 程度の時間がかかっているため、2回目以降はその時間だけツールのレスポンスが早くなります。

タイマー値の OCR 処理

ゲーム画面の位置推定が終わったら、タイマー値がある位置を切り取り Tesseract OCR にて処理します。

OCR 処理結果の取り込み

タイマー値の種類は「遠征」「入渠」「建造」の3種類がありますが、それらのタイマー文字列の場所と大きさはツールの data フォルダにある number_positions.yaml で管理しています。タイマー位置の定義をファイルにしているのは、いずれ UI が微調整されたときに各ユーザでも対応できるようするためです。
data/number_positions.yaml の全文

# Mission
- 1:
? - size: 88x17
? - positions:
??? - 0: +710+391

# Repair
- 2:
? - size: 102x23
? - positions:
??? - 0: +610+160
??? - 1: +610+241
??? - 2: +610+322
??? - 3: +610+403

# Create
- 3:
? - size: 100x26
? - positions:
??? - 0: +394+181
??? - 1: +394+259
??? - 2: +394+337
??? - 3: +394+415

# Mission name
- 4:
? - size: 128x1
? - positions:
??? - 0: +584+118

このツールでは、このファイルで定義された位置の矩形画像に Tesseract OCR を用いた OCR 処理を行います。OCR 処理で得られた文字列が「01:23:45」のように、数値とコロンから構成されていた場合のみ、読み取りが成功したとみなしています。

target_2.0

現状では OCR は tesseract.exe をパッケージに含めて実行してますが、これは Windows の MinGW でのビルドでは Tesseract OCR をライブラリとしてリンクすると実行ファイルである bath_timer.exe の実行に失敗するようになったためです。今でもこの問題の解決方法は調査できていません。

OCR 処理の順番決め

タイマー値には「遠征」「入渠」「建造」の種類がありますが、これらが同時に表示されることはなく、ゲーム画面には1種類しか表示されていません。なので、このツールでは現在のシーンの推定を行い、タイマー値がない場所への OCR 処理を減らすようにしています。

  • やっていること
    • ゲーム画面の画素の色から現在のシーンを推定する。
    • あるシーンのタイマー値が取得できたら、他のシーンのタイマー値の OCR 処理は行わない。
    • 推定したシーンのタイマー値が取得できなかったら、他のシーンのタイマー値について OCR 処理を行う。

scene_estimate_mark? 推定に用いる画素の位置

1回の OCR 処理には 30 ms から 80 ms 程度の時間がかかるため、このような対処を行うことで、(それなりには) ツールのレスポンスを改善しています。

「遠征」の OCR 処理について

遠征以外については、タイマー値の場所が固定なのですが、遠征のみ「遠征の種類」「その遠征のタイマー値」といった構成になっています。

「今のタイマー値がどの遠征名のものなのか」を処理するために、このツールでは遠征名の画像に対応するキーを生成し、そのキーにタイマー値を対応させています。

具体的には、遠征名から 128 x 1 サイズの画像を切り取り、それの CRC 結果をキーとして利用しています。これにより「遠征1」のタイマー値と「遠征2」のタイマー値を区別しています。

mission_rects

取り込んだタイマー値の保存

取り込んだタイマー値は、タイマー値を PC が取り込んだ時刻と取り込んだ値をペアで timer_items.csv というファイルに出力して保存しています。これにより任意の時刻にけるタイマーの残り時間が一意に決まります。

将来的なゲーム UI 変更への対処

私がプログラマでいる限り必要だと思ったメンテナンスは行うつもりですが、私のメンテナンスに我慢できない人がいるかもしれないので、このツールはオープンソースで開発しています。

また、ゲーム UI 変更に伴ってゲーム画面のサイズ変更やタイマー値の位置変更がなされた場合のために、ユーザでも対処できるようにゲーム画面認識用のテンプレート画像やタイマー文字列位置の定義ファイルはツールの data フォルダに配置してあります。(もちろん、このツールが必要なくなる UI 変更は大歓迎です!)

最後に

この記事において誤記、およびわかりにくい箇所があればお知らせ下さい。
修正いたします。

SICK LMS5xx 用の C++ ドライバの作成 (強度情報を取得できるようにした)

暇なわけではないが、メイン仕事をする気が起きなかったので Lms_driver.cpp に強度情報を取得するあたりの機能を実装した。
https://bitbucket.org/satofumi/hobby_robot_sdk/src/b5734dc0ba50bf78957748e978cf05223d2d1f3d8/lib/lidar/Lms_driver.cpp?at=default

lms_viewer_2013_1210
オレンジ色のプロットが強度情報

正面に回帰反射版を置いたところ、そこの値が 16 進数の 8 bit 表記で 0xFE になっているのが確認できた。(0xFF には、ならないようだ)

強度データが 0xFE になる特性を利用すれば、反射版かどうかの判定が簡単にできるはず。是非、次回の実験時にこのあたりの情報をうまく使っていきたい。

残るは複数エコーを取得するあたりだが、その実装はまた今度にしたい。