そろそろ画像修正ツールが出来上がってきたので、学生のエクスペリア(2.1)を使ってテストテストーー。
すると、ガツガツ落ちる。 いやいや。 落ちること落ちること。
原因はタイトル通りBitmapFactoryのdecodeStreamでoutofMemory
うぇー。 IS01だと起きないのになぁ。 あれか。カメラの解像度が高すぎるからか。
てことで、調べたら、エクスペリアの最大の解像度は8Mピクセル!! サイズにすると3264×2448 !!!?
なんとまぁ。 それをARGB_8888で取ったらー。 大体容量32M。そりゃ落ちるわ。
対応としては、BitmapFactory.Optionsを上手く指定すればいいらしい。
家帰ったらやってみよう。
2010年11月29日月曜日
2010年11月26日金曜日
IS01
僕が持っているAndroid端末はIS01だけなんだけども。
まぁ、OSがアップデートされないのはよしとしよう。 実機チェックとしてはVerは高いより低いほうがなにかと便利だしね。
ただ、プロセスの暴走だけはなんとかしてくれんかなー。
最近のアップデートから、uimdっちゅープロセスも気付くと暴走していることが多い。
熱中して開発してたらPCからのUSB充電じゃ間に合わなくて、電源落ちたりするし。 やめとくれ。
まぁ、OSがアップデートされないのはよしとしよう。 実機チェックとしてはVerは高いより低いほうがなにかと便利だしね。
ただ、プロセスの暴走だけはなんとかしてくれんかなー。
最近のアップデートから、uimdっちゅープロセスも気付くと暴走していることが多い。
熱中して開発してたらPCからのUSB充電じゃ間に合わなくて、電源落ちたりするし。 やめとくれ。
電子書籍が最近話題だけども
最近、近くの技術書の揃いがグンバツの本屋さんが潰れちゃって途方に暮れてたんだけど、電子書籍なんか流行ろうもんなら本屋はますます潰れるよね。
しかしながら、いまいち電子書籍のウリがわかんねぃ。
エコですか。 紙使わないからエコですか。 んじゃぁ、エコポイントとかくれればいいのに。
そもそも紙使わないから安く売れるとか?
広告がズバズバカットインするから無料とか?
まぁ、値段で勝負ですよね。普通に考えれば。
あと「検索」か。
夜中とかに
「あれ、この台詞なんだっけ!!? どの漫画の誰の台詞だっけ!!!?」
って眠れぬ夜にはいいかもしれない。(最近では『犬みたいに同じところでぐるぐる回ってろ』みたいな台詞がどこ出展だったか思い出せなくて苦労した。 BLACK LAGOONだった。あふん。)
しかし。
冒頭にもどるけど、本屋が生き残る道はあるんだろうか。
ちょっと考えるとーーー。
本屋のウリって、「実物感」であったり、店員さんの趣味丸出しの「品揃え」だったり、技術書や小説で言うと「立ち読み」だったりだと思う。
すると、それをそのまま電子書籍に当てはめると、本屋はwifiのフリースポットみたいな状態になって、本を揃える(試し読みをする権利を買う)。
ユーザーは本屋に行くと、電子書籍が試し読み出来る。
んで、そこで購入すると、本屋にマージンが入る。 ・・・・とか?
駄目だ。本屋で立ち読み(試し読み)して、家帰ってから購入されちゃったらアウトだ。
ってーいうか、それって正に今の「本屋で立ち読みして、良さそうだったらAmazonで注文」の状況だし。
難しいね。
個人的には本屋さんには頑張っていただきたい。
華氏451度みたいになってもらっても困る。
しかしながら、いまいち電子書籍のウリがわかんねぃ。
エコですか。 紙使わないからエコですか。 んじゃぁ、エコポイントとかくれればいいのに。
そもそも紙使わないから安く売れるとか?
広告がズバズバカットインするから無料とか?
まぁ、値段で勝負ですよね。普通に考えれば。
あと「検索」か。
夜中とかに
「あれ、この台詞なんだっけ!!? どの漫画の誰の台詞だっけ!!!?」
って眠れぬ夜にはいいかもしれない。(最近では『犬みたいに同じところでぐるぐる回ってろ』みたいな台詞がどこ出展だったか思い出せなくて苦労した。 BLACK LAGOONだった。あふん。)
しかし。
冒頭にもどるけど、本屋が生き残る道はあるんだろうか。
ちょっと考えるとーーー。
本屋のウリって、「実物感」であったり、店員さんの趣味丸出しの「品揃え」だったり、技術書や小説で言うと「立ち読み」だったりだと思う。
すると、それをそのまま電子書籍に当てはめると、本屋はwifiのフリースポットみたいな状態になって、本を揃える(試し読みをする権利を買う)。
ユーザーは本屋に行くと、電子書籍が試し読み出来る。
んで、そこで購入すると、本屋にマージンが入る。 ・・・・とか?
駄目だ。本屋で立ち読み(試し読み)して、家帰ってから購入されちゃったらアウトだ。
ってーいうか、それって正に今の「本屋で立ち読みして、良さそうだったらAmazonで注文」の状況だし。
難しいね。
個人的には本屋さんには頑張っていただきたい。
華氏451度みたいになってもらっても困る。
2010年11月25日木曜日
ProgressDialogを上手く使う
昨日、「あの保存とかするときにくるくる回ってる砂時計替わりみたいなの出したい」的な事を書いたんですが、ProgressDialogなんですね。 ふむん。
で。
これの使い道っていうと、重い処理を別スレッドで動かして、その間に表示。
処理が終了したら閉じる。 ってなる。
なので、重い処理の開始前にshow()して、処理が終わったらdismiss()を呼ぶ。
でも、その「重い処理」ってーのは、別スレッドなので、別スレッドからshow()すると、RuntimeExceptionだしてくれるんだよね。コイツ。(Toastでも同じ現象発生)
んで、Handlerを使えとかなんとか言われるわけなんだけど。
なんとかクラスでまとめられないかなーと思って、作ってみました。
肝は、createDialogより前にinitを呼ぶということ。
さらに言えば、initはviewのスレッドから呼ぶ必要があるっぽいです(てか、無きゃinitとcreateに分ける必要が無い)
正直、ここらへんは行き当たりばったりというか、やってみたら出来た。というか。
理論に基づいた作りじゃないのでなにか間違ってるかもですが。とりあえず、今のところ問題無しです。
で。
これの使い道っていうと、重い処理を別スレッドで動かして、その間に表示。
処理が終了したら閉じる。 ってなる。
なので、重い処理の開始前にshow()して、処理が終わったらdismiss()を呼ぶ。
でも、その「重い処理」ってーのは、別スレッドなので、別スレッドからshow()すると、RuntimeExceptionだしてくれるんだよね。コイツ。(Toastでも同じ現象発生)
んで、Handlerを使えとかなんとか言われるわけなんだけど。
なんとかクラスでまとめられないかなーと思って、作ってみました。
package mosaic.dividebyzero.net; import android.app.ProgressDialog; import android.content.Context; import android.os.Handler; class MyProgressDialog implements Runnable { private String title, message; private static ProgressDialog progressDialog; private static Handler handle = new Handler(); public static void init(Context context) { if (progressDialog == null) progressDialog = new ProgressDialog(context); } public static void createDialog(String title, String message) { if (progressDialog == null) throw new RuntimeException("MyProgressDialog is not initialize\nplease call init Method."); handle.post(new MyProgressDialog(title, message)); } public static void close() { if (progressDialog != null) progressDialog.dismiss(); } public MyProgressDialog(String title, String message) { this.title = title; this.message = message; } @Override public void run() { // TODO 自動生成されたメソッド・スタブ progressDialog.setTitle(title); progressDialog.setMessage(message); progressDialog.setIndeterminate(false); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setCancelable(true); progressDialog.show(); } }
肝は、createDialogより前にinitを呼ぶということ。
さらに言えば、initはviewのスレッドから呼ぶ必要があるっぽいです(てか、無きゃinitとcreateに分ける必要が無い)
正直、ここらへんは行き当たりばったりというか、やってみたら出来た。というか。
理論に基づいた作りじゃないのでなにか間違ってるかもですが。とりあえず、今のところ問題無しです。
SDに保存した画像がすぐに認識しない件
SDカードに画像を保存した直後は、何故かギャラリー系のアプリから見ることが出来ないんですよね。
一回PCへマウントして、アンマウントしたり、OS自体を再起動したりすれば見れるんですけども。 なんでしょうか。これは。
でも、touch2pixelとかはちゃんと保存した後もすぐ見れるんですよね。これがまた。
なにか特別な保存方法があるんだろうかー。
って、調べてみたら。
ContentResolverってので登録しなきゃいけないんですね。 サムネイル絡みかと思ってたら、こんなのがあるとは・・・。
一応コード
これまたはまったのが、Images.Media.DATE_MODIFIED には更新時間を入れるんだけど、ちょっとぐぐると
「System.currentTimeMillis()」が平気で指定されてるところ。
でも、これで保存すると、2037年とかになっちゃうんですよな。
ここで指定するのは1970年1月1日からの~ってとこまでは一緒なんだけど、「秒数」を入れるらしい。
んで、System.currentTimeMillis()は1970年起点の「ミリ秒」なので、時間が狂う。と。
ちゅーわけで、/1000が要るわけです。 ふむん。
完成が近づいてきたぜー
一回PCへマウントして、アンマウントしたり、OS自体を再起動したりすれば見れるんですけども。 なんでしょうか。これは。
でも、touch2pixelとかはちゃんと保存した後もすぐ見れるんですよね。これがまた。
なにか特別な保存方法があるんだろうかー。
って、調べてみたら。
ContentResolverってので登録しなきゃいけないんですね。 サムネイル絡みかと思ってたら、こんなのがあるとは・・・。
一応コード
// 保存先を取得 String status = Environment.getExternalStorageState(); File fout = null; if (!status.equals(Environment.MEDIA_MOUNTED)) { // SDカードがマウントされてないので、システムの使える場所に保存 fout = getContext().getFilesDir(); } else { // SDカードがマウントされているので、勝手にフォルダ作成 fout = new File("/sdcard/ciasom/"); fout.mkdirs(); } File fname = new File(fout ,"/ciasom" + getDate() + ".png"); FileOutputStream fos = new FileOutputStream(fname); bitmap.compress(CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); //メディアに登録作業が必要らしい。 ContentValues values = new ContentValues(); ContentResolver contentResolver = getContext().getContentResolver(); values.put(Images.Media.MIME_TYPE, "image/png"); values.put(Images.Media.DATE_MODIFIED,System.currentTimeMillis()/1000); values.put(Images.Media.SIZE, fname.length()); values.put(Images.Media.TITLE, fname.getName()); values.put(Images.Media.DATA, fname.getPath()); contentResolver.insert(Media.EXTERNAL_CONTENT_URI, values);これは今作っている可逆モザイクアプリのソースそのままぶっこぬいてきました。
これまたはまったのが、Images.Media.DATE_MODIFIED には更新時間を入れるんだけど、ちょっとぐぐると
「System.currentTimeMillis()」が平気で指定されてるところ。
でも、これで保存すると、2037年とかになっちゃうんですよな。
ここで指定するのは1970年1月1日からの~ってとこまでは一緒なんだけど、「秒数」を入れるらしい。
んで、System.currentTimeMillis()は1970年起点の「ミリ秒」なので、時間が狂う。と。
ちゅーわけで、/1000が要るわけです。 ふむん。
完成が近づいてきたぜー
2010年11月24日水曜日
カメラをintentで外部起動して、指定した場所に保存してもらう
最近はゲームはさておき、自分がほしいな。 っていうツールを作るのでいっぱいいっぱいです。 kszです。
今は可逆モザイクアプリを作ろうと思っているんだけども、当然元の画像はギャラリーから持ってきたり、カメラから取得しなきゃなので、調べつつつくっていたんですが、ハマりまくりました。
まず、カメラから戻ってきた(onActivityResultの引数の)Intent の data には縮小した画像が入ってしまうということ。
これはIntentに受け渡せるデータ量の上限が決まっているかららしい。 まずこれで1ハマリ。
ではでは、EXTRA_OUTPUT で、urlを指定して、指定した場所に保存をしてもらおう。と。
具体的には
逆を言えば、何か外部からグローバルのintent呼び出しを自分のアプリがうけた場合は、このEXTRA_OUTPUTが入っていた場合はそこに保存するようにしなきゃって事ですよな。
それはさておき。
では、それでonActivityResultで受け取ろうーって思ったんだけど、
ってやったら、ヌルポが飛ぶ。 何が!? って調べると、そもそもIntent data のdataがnull。
EXTRA_OUTPUTを指定しちゃうと、戻りのIntentがnullになる・・・。 んですか・・・?
腑に落ちねぇ・・・。
今は可逆モザイクアプリを作ろうと思っているんだけども、当然元の画像はギャラリーから持ってきたり、カメラから取得しなきゃなので、調べつつつくっていたんですが、ハマりまくりました。
まず、カメラから戻ってきた(onActivityResultの引数の)Intent の data には縮小した画像が入ってしまうということ。
これはIntentに受け渡せるデータ量の上限が決まっているかららしい。 まずこれで1ハマリ。
ではでは、EXTRA_OUTPUT で、urlを指定して、指定した場所に保存をしてもらおう。と。
具体的には
putExtra(MediaStore.EXTRA_OUTPUT, [ここに保存してほしい場所をurlで]);ふむ。
逆を言えば、何か外部からグローバルのintent呼び出しを自分のアプリがうけた場合は、このEXTRA_OUTPUTが入っていた場合はそこに保存するようにしなきゃって事ですよな。
それはさておき。
では、それでonActivityResultで受け取ろうーって思ったんだけど、
protected void onActivityResult(int requestCode, int resultCode, Intent data) { String url = data.getStringExtra(MediaStore.EXTRA_OUTPUT); //↑で受け取ったurlから画像ファイル読み込み処理をここから下に }
ってやったら、ヌルポが飛ぶ。 何が!? って調べると、そもそもIntent data のdataがnull。
EXTRA_OUTPUTを指定しちゃうと、戻りのIntentがnullになる・・・。 んですか・・・?
腑に落ちねぇ・・・。
2010年11月17日水曜日
eclipseショートカット覚書
Ctrl + Shitf + B
でブレークポイント設置/解除
うーん。 F9がみに染み付いていて困る。 VisualStudioショートカットに全部変えてしまいたい・・・。
でブレークポイント設置/解除
うーん。 F9がみに染み付いていて困る。 VisualStudioショートカットに全部変えてしまいたい・・・。
2010年11月15日月曜日
マイフェイバリットな壁紙
人は皆「マイフェイバリット壁紙」を持っている。
しかし、得てして「マイフェイバリット壁紙」は人に見られるとまずい場合が多い。 例えば、エロすぎたり。例えば、その人のキャラに合わないぐらい可愛かったり。
なので、誰かに見られる可能性がある時はまともな壁紙に変更し、家に帰ってプライベートスペースが確保できたらマイフェイバリットな壁紙に変更する。
でも、この作業が面倒くさい。 なぜなら、マイフェイバリット壁紙がその他の壁紙達に紛れ込んでしまうから。
そして僕は考えた。 「壁紙を即座に切り替えるアプリケーションは無いだろうか」
さがすと、結構ある。 けど、多機能過ぎる。 常駐してほしいわけじゃないし、ランダムで画像変える~とかもいらんのだ。
ただ単純に「起動したら、今の壁紙をまともな壁紙に変更して即終了。 その逆も可」ってのが欲しいんだ。
僕が捜した感じでは無い。
無い。なら。作れ。
しかし、得てして「マイフェイバリット壁紙」は人に見られるとまずい場合が多い。 例えば、エロすぎたり。例えば、その人のキャラに合わないぐらい可愛かったり。
なので、誰かに見られる可能性がある時はまともな壁紙に変更し、家に帰ってプライベートスペースが確保できたらマイフェイバリットな壁紙に変更する。
でも、この作業が面倒くさい。 なぜなら、マイフェイバリット壁紙がその他の壁紙達に紛れ込んでしまうから。
そして僕は考えた。 「壁紙を即座に切り替えるアプリケーションは無いだろうか」
さがすと、結構ある。 けど、多機能過ぎる。 常駐してほしいわけじゃないし、ランダムで画像変える~とかもいらんのだ。
ただ単純に「起動したら、今の壁紙をまともな壁紙に変更して即終了。 その逆も可」ってのが欲しいんだ。
僕が捜した感じでは無い。
無い。なら。作れ。
現在の壁紙をゲームの背景にする
ContextWrapper.getWallpaper();でDrawableが取れるので、それをー・・・って感じなんだけど、最終的に描画するためにBitmapが欲しい(OenGLでテクスチャを作るためにもBitmapが欲しい)ので、
// 現在の壁紙を取得 Bitmap wallpaper = ((BitmapDrawable) getWallpaper()).getBitmap();てな感じ。
ActivityはContextWrapperを継承だか実装だかしてるぽいので、殆どの場合が直呼び出し。
しかし、BitmapDrawableでキャストするって・・・。 低いVerだと使えないってことかな。
2010年11月11日木曜日
Eclipseでandroid開発していると度々フリーズする件
EclipseにはVisualStudioでいうところのInterisenceがProposal(プロポーザル)とかいう名前であって、便利で良いことなんだけども、候補をだした瞬間度々止まるので非常にイラつく。
そのせいで、最近ではプロポーザル機能自体を消したりしてたんだけども、やっぱり復活してほしい。
んで、なんでそこで止まっちゃうのか。
多分なんだけど、本当はプロポーザルで候補表示と同時に、ソースに書いてあるjavadocを表示してくれるようになっていて。 でも、androidSDKはclassが詰まったjarファイルしかないので、ソースを探しに行ってる時間がでフリーズするんじゃないか。
と、いうのも逆説的で。
試しにandroidSDKのソースを関連付けたら、ピタっ!!っとプロポーザル時のフリーズがなくなったのできっとそうなんじゃないかなー。
このソースの関連付けですが、これはこれで結構罠がありました。
jarをコンパイルしなおすとか、ビルドパス構成でjarファイルをさらに追加してソースフォルダを指定するとか。 これまたぐぐるとたくさんでてくるんですが、どれも僕は失敗しました。(conversion to dalvik format failed with error 1 とか言われたり)
で、結局たどり着いた方法が
「android.jar と同じ階層に sources という名のフォルダを作って、その中にソースファイルをコピー」
でした。
簡単だし、eclipseの設定をいじるわけではないので、新規プロジェクトつくるたびに設定とかしなくてもいい!!! これでウッドボール!!!
そのせいで、最近ではプロポーザル機能自体を消したりしてたんだけども、やっぱり復活してほしい。
んで、なんでそこで止まっちゃうのか。
多分なんだけど、本当はプロポーザルで候補表示と同時に、ソースに書いてあるjavadocを表示してくれるようになっていて。 でも、androidSDKはclassが詰まったjarファイルしかないので、ソースを探しに行ってる時間がでフリーズするんじゃないか。
と、いうのも逆説的で。
試しにandroidSDKのソースを関連付けたら、ピタっ!!っとプロポーザル時のフリーズがなくなったのできっとそうなんじゃないかなー。
このソースの関連付けですが、これはこれで結構罠がありました。
jarをコンパイルしなおすとか、ビルドパス構成でjarファイルをさらに追加してソースフォルダを指定するとか。 これまたぐぐるとたくさんでてくるんですが、どれも僕は失敗しました。(conversion to dalvik format failed with error 1 とか言われたり)
で、結局たどり着いた方法が
「android.jar と同じ階層に sources という名のフォルダを作って、その中にソースファイルをコピー」
でした。
簡単だし、eclipseの設定をいじるわけではないので、新規プロジェクトつくるたびに設定とかしなくてもいい!!! これでウッドボール!!!
androidでBGM再生
効果音はできたので、今度はBGM
MediaPlayerが使えるのだけど、曲と曲のつなぎにフェードインフェードアウトとか、すでにその曲を再生中の時には再生しないなどの管理を毎回やるのは面倒なので、やっぱりマネージャーっぽいものを作成
前の効果音の時もそうだったんだけど、リソースのデータを読みたい時って、Contextが必要になってくるので、それをいかにしてマネージャークラスに渡すかってのが悩みどころ。
僕はもうOpenGLが使えるGLViewクラスをシングルトンぽくしているので、そっからgetContext()なんだけどーー。 普通はどうやるんですかね。
MediaPlayerが使えるのだけど、曲と曲のつなぎにフェードインフェードアウトとか、すでにその曲を再生中の時には再生しないなどの管理を毎回やるのは面倒なので、やっぱりマネージャーっぽいものを作成
package dividebyzero.net; import android.media.MediaPlayer; public class BgmManager { static BgmManager instance = new BgmManager(); private MediaPlayer player; private int currentPlayBgm; private int nextPlayBgm; private int vol, targetVol; enum PLAY_STAT{ STOP,FADEIN,PLAYING,FADEOUT; } private PLAY_STAT stat; private BgmManager() { stat = PLAY_STAT.STOP; currentPlayBgm = 0; nextPlayBgm = 0; vol = 100; targetVol = 100; } public static BgmManager get() { return instance; } public static void release() { instance.stop(); instance = null; } public void play(int id, boolean isFade) { if (id == currentPlayBgm) { // 現在再生しているので何もしない return; } else { nextPlayBgm = id; stat = PLAY_STAT.FADEOUT; } } public void update() { switch (stat) { case STOP: stop(); if(nextPlayBgm != 0){ currentPlayBgm = nextPlayBgm; nextPlayBgm = 0; stat = PLAY_STAT.FADEIN; } break; case FADEIN: if (player == null) { player = MediaPlayer.create(GLView.get().getContext(), currentPlayBgm); player.setLooping(true); player.start(); vol = 0; player.setVolume(vol/100.0f, vol/100.0f); } vol += 2; if (targetVol < vol) { vol = targetVol; stat = PLAY_STAT.PLAYING; } player.setVolume(vol/100.0f, vol/100.0f); break; case PLAYING: break; case FADEOUT: if (player != null) { vol -= 2; if (vol < 0) { vol = 0; stat = PLAY_STAT.STOP; } player.setVolume(vol/100.0f, vol/100.0f); } else { stat = PLAY_STAT.STOP; } break; } } public void stop() { // 現在の曲を止める if (player != null) { player.stop(); player.release(); player = null; } } public void setVolume(int vol) { this.vol = vol; } public int getVolume() { return vol; } }
前の効果音の時もそうだったんだけど、リソースのデータを読みたい時って、Contextが必要になってくるので、それをいかにしてマネージャークラスに渡すかってのが悩みどころ。
僕はもうOpenGLが使えるGLViewクラスをシングルトンぽくしているので、そっからgetContext()なんだけどーー。 普通はどうやるんですかね。
2010年11月8日月曜日
androidで効果音マネージャ
やっぱりゲームには効果音が必要なので、調べると、SoundPoolってのが良いらしい。
ところで、ゲーム作ったことがある人には常識だけど、同じフレーム内で同じ音声を鳴らしたって意味が無い。むしろ読み込みやらなんやらで負荷が増大してるはず。
なので、効果音を鳴らしたい時に、直で鳴らすのではなく、「鳴らしたい予約」をしておいて、あとで予約されているものを全て鳴らすべき。
さらに言えば、60fpsで動いてるとして、1フレーム目に鳴らした音を2フレーム目に鳴らしてもやっぱり無駄。 なので、前回再生フレームを覚えておいて、ある程度の間隔があった場合だけ再生するようにするのがよさそう(今回はまだここまでやってないけど)
と、いうわけで、こんな感じでSoundManagerを作ってみた。
使い方としては、効果音(出来ればogg)をres-rawフォルダに突っ込んで、
という感じ。
文字列がキーになっているのが、ちょっとオーバーヘッドありそうですが、気になる人はget()の戻り値がSoundManager型なので、確保しておいてplay()すりゃー良いと思います。
ちょっとSoundPoolのインスタンスの作る場所が気に食わないけど、初期化タイミングが難しいですよなぁ。
もうちょっと修正する予定。
これとは別に、BGMでループ再生とかにはMediaPlayerを使う必要がありそうです。
ところで、ゲーム作ったことがある人には常識だけど、同じフレーム内で同じ音声を鳴らしたって意味が無い。むしろ読み込みやらなんやらで負荷が増大してるはず。
なので、効果音を鳴らしたい時に、直で鳴らすのではなく、「鳴らしたい予約」をしておいて、あとで予約されているものを全て鳴らすべき。
さらに言えば、60fpsで動いてるとして、1フレーム目に鳴らした音を2フレーム目に鳴らしてもやっぱり無駄。 なので、前回再生フレームを覚えておいて、ある程度の間隔があった場合だけ再生するようにするのがよさそう(今回はまだここまでやってないけど)
と、いうわけで、こんな感じでSoundManagerを作ってみた。
package dividebyzero.net; import java.util.HashMap; import android.content.Context; import android.media.AudioManager; import android.media.SoundPool; public class SoundManager { // 個々のサウンド public SoundManager(int sndId) { this.sndId = sndId; this.isPlay = false; } private int sndId; private boolean isPlay; private float leftVol, rightVol; public void play(float leftVol, float rightVol) { this.leftVol = leftVol; this.rightVol = rightVol; this.isPlay = true; } public void play(int vol) { play(vol, vol); } public void play() { play(100, 100); } // 管理スタティックゾーン private static HashMap<String, SoundManager> soundMap = new HashMap<String, SoundManager>(); private static SoundPool sp; private static Context _context; public static SoundManager get(String name) { return soundMap.get(name); } public static void init(Context context) { _context = context; } // 予約されたものを全部再生 public static void playAll() { for (SoundManager obj : soundMap.values()) { if (obj.isPlay) { sp.play(obj.sndId, obj.leftVol, obj.rightVol, 1,0, 1f); obj.isPlay = false; } } } public static SoundManager add(int id, String name) { SoundManager sm = soundMap.get(name); if (sm == null) { if (sp == null) sp = new SoundPool(10, AudioManager.STREAM_MUSIC, 100); sm = new SoundManager(sp.load(_context, id, 1)); soundMap.put(name, sm); } return sm; } public static void release() { sp.release(); } }
使い方としては、効果音(出来ればogg)をres-rawフォルダに突っ込んで、
public void init(){ SoundManager.add(R.raw.jump,"適当な名前"); } public void update(){ if(ボタンを押したら){ SoundManager.get("適当な名前").play(); } //////////////////////////////////最後に SoundManager.playAll(); }
という感じ。
文字列がキーになっているのが、ちょっとオーバーヘッドありそうですが、気になる人はget()の戻り値がSoundManager型なので、確保しておいてplay()すりゃー良いと思います。
ちょっとSoundPoolのインスタンスの作る場所が気に食わないけど、初期化タイミングが難しいですよなぁ。
もうちょっと修正する予定。
これとは別に、BGMでループ再生とかにはMediaPlayerを使う必要がありそうです。
2010年11月5日金曜日
傾きを取るために
今までは「方位センサー」で傾きを取っていたんだけども、もしかして世間様は「加速度センサー」で傾きを取ってらっしゃる? のか?
確かにどっちでも取れるんだけど、「方位センサー」の方が戻ってくるのが360度の角度の範囲で帰ってくるから、楽とか思って方位なんだけどーーーーうーーん。
どっちがどういう利点があって、どういう欠点があるのかを言及したサイトが特に見つからない。
なんだろう。
ともかく操作性がよくなる方を使おう。
確かにどっちでも取れるんだけど、「方位センサー」の方が戻ってくるのが360度の角度の範囲で帰ってくるから、楽とか思って方位なんだけどーーーーうーーん。
どっちがどういう利点があって、どういう欠点があるのかを言及したサイトが特に見つからない。
なんだろう。
ともかく操作性がよくなる方を使おう。
2010年11月4日木曜日
UIを考える
ゲームに置いてユーザーインターフェースっていうのはかなりの割合を占めると思う。
んで、androidで問題になるのが、「キーボードが存在しない」ということ。
いや、しないんじゃなくて、「存在することが確定できない」という状態。多分日本で一番普及しているであろうエクスペリアはキーボード付いてないわけだし。
と、いうわけで、使える入力装置が非常に限られる。
確実にAndroid端末ならついてるのが 「タッチパネル」なんだけど。
ところが、マルチタッチは存在確定しない。 先に出てきたエクスペリアもマルチタッチ非対応。 IS01はなんかあるけど、OSレベルでは対応してないし。
すると、どうするんだ。 シューティングゲームすらまともに作れないじゃないか。
僕がちょっと見かけたものだと、弾はでっぱなしで、操作だけをタッチパネルのドラッグで行うというもの。
これは果たして「シューティング」といえるのか。
んで、もう一個、ほぼ確実にあると言われているのが「加速度センサー」および「傾きセンサー」
(僕が知る限りはToshibaのdynabook AZに付いてない)
さっき例に出したシューティングだとして。
傾きでプレイヤーの上下左右移動を行い、タップでショット。
こ・・・これか・・・? これなのか・・・・?
とりあえず、作ってみよう・・・。
んで、androidで問題になるのが、「キーボードが存在しない」ということ。
いや、しないんじゃなくて、「存在することが確定できない」という状態。多分日本で一番普及しているであろうエクスペリアはキーボード付いてないわけだし。
と、いうわけで、使える入力装置が非常に限られる。
確実にAndroid端末ならついてるのが 「タッチパネル」なんだけど。
ところが、マルチタッチは存在確定しない。 先に出てきたエクスペリアもマルチタッチ非対応。 IS01はなんかあるけど、OSレベルでは対応してないし。
すると、どうするんだ。 シューティングゲームすらまともに作れないじゃないか。
僕がちょっと見かけたものだと、弾はでっぱなしで、操作だけをタッチパネルのドラッグで行うというもの。
これは果たして「シューティング」といえるのか。
んで、もう一個、ほぼ確実にあると言われているのが「加速度センサー」および「傾きセンサー」
(僕が知る限りはToshibaのdynabook AZに付いてない)
さっき例に出したシューティングだとして。
傾きでプレイヤーの上下左右移動を行い、タップでショット。
こ・・・これか・・・? これなのか・・・・?
とりあえず、作ってみよう・・・。
当たり判定高速化
ゲームと言えば当たり判定なので、ここを最大限スリムにしておくに越したことはないはず。
作りたいゲームにもよるけど、基本は矩形(四角と四角)で良いと思う。 ゲームによっては円と円にするけども。
まぁ、矩形で考えて、(x1,y1)-(x2,y2)の四角と(x3,y3)-(x4,y4)の四角で当たり判定するとして普通に作ると
という感じ。
書いてて思ったけど、intを8個引数で渡すのってどうなんだ。 int(4Byte)*8=32Byte? うーん?
ゲームの座標で4Byteも必要ないからshortでいいのか。
もしくは
ってクラスを作って、参照渡ししたほうがいいのか。
まぁ、それはさておき、高速化の基本はif文を除く事だと思うので、最適化をしまくっていくと
と、if文を削れるところまで行ける。
んじゃぁ、実際これが速いのかどうなのか。 実際にランダム座標で100,000回処理のタイムを測ってみると
~1回目~
最適化前:45,111ms
最適化後:45,246ms
~2回目~
最適化前:45,197ms
最適化後:45,944m
あるぇ~~~。
最適化したほうが遅い!!! うっはーー!!!
これは座標にもよるけど、全てのものが重なってるってことはほとんど無いはずなので、if文方式は途中であたってない事が確定してfalseが返って、あとの処理がスキップされることによる結果だと思う。
ええ、じゃぁ、if文方式でいいってことですか。
ちなみにint4つ渡すオーバーヘッドを減らすべく、クラスで参照渡し方式にしてみたら
参照渡し方式:44,800ms
あ、若干マシ・・・。
と、いうわけで、最終的に
を使って、
が最速でFA???
まぁ、 100,000回実行なので、実際には目に分かるような差はないんだけども。
目指せ25ドル!
作りたいゲームにもよるけど、基本は矩形(四角と四角)で良いと思う。 ゲームによっては円と円にするけども。
まぁ、矩形で考えて、(x1,y1)-(x2,y2)の四角と(x3,y3)-(x4,y4)の四角で当たり判定するとして普通に作ると
boolean hitCheck(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){ if(x4 < x1)return false; if(y4 < y1)return false; if(x3 > x2)return false; if(y3 > y2)return false; return true; }
という感じ。
書いてて思ったけど、intを8個引数で渡すのってどうなんだ。 int(4Byte)*8=32Byte? うーん?
ゲームの座標で4Byteも必要ないからshortでいいのか。
もしくは
class Rect{ public int x1,y1,x2,y2; }
ってクラスを作って、参照渡ししたほうがいいのか。
まぁ、それはさておき、高速化の基本はif文を除く事だと思うので、最適化をしまくっていくと
boolean hitCheck(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){ final boolean boolean_c[] = {false,true}; return boolean_c[((x1-x4) & (x3-x2) & (y1-y4) & (y3-y2)) >>> 31]; }
と、if文を削れるところまで行ける。
んじゃぁ、実際これが速いのかどうなのか。 実際にランダム座標で100,000回処理のタイムを測ってみると
~1回目~
最適化前:45,111ms
最適化後:45,246ms
~2回目~
最適化前:45,197ms
最適化後:45,944m
あるぇ~~~。
最適化したほうが遅い!!! うっはーー!!!
これは座標にもよるけど、全てのものが重なってるってことはほとんど無いはずなので、if文方式は途中であたってない事が確定してfalseが返って、あとの処理がスキップされることによる結果だと思う。
ええ、じゃぁ、if文方式でいいってことですか。
ちなみにint4つ渡すオーバーヘッドを減らすべく、クラスで参照渡し方式にしてみたら
参照渡し方式:44,800ms
あ、若干マシ・・・。
と、いうわけで、最終的に
class HitRect{ public int x1,y1,x2,y2; }
を使って、
public static boolean hitCheck(HitRect a,HitRect b) { if (b.x2 < a.x1)return false; if (b.y2 < a.y1)return false; if (b.x1 > a.x2)return false; if (b.y1 > a.y2)return false; return true; }
が最速でFA???
まぁ、 100,000回実行なので、実際には目に分かるような差はないんだけども。
目指せ25ドル!
eclipseショートカット
これは使える! ってのを覚書
Ctrl + Shift + t
Ctrl + Alt + h
Alt + Shift + s
三つ押し系はちょっと簡単には覚えられないのでこういう所に書いとかなきゃねー。
Ctrl + Shift + t
Ctrl + Alt + h
Alt + Shift + s
三つ押し系はちょっと簡単には覚えられないのでこういう所に書いとかなきゃねー。
2010年11月2日火曜日
Androidメモ
いろいろな基礎をすっ飛ばして、Eclipseで開発。OpenGLを使って画面をしてみた。
ただそれだけなのだけど、とてつもなく罠があったのでここに書いておく。
・Eclipseの日本語化プラグインを入れると、なぜかビューの追加が出来ないようになったり、キーバインドが消えたりする(ctrl+tabでソースの切り替えが出来ないと開発効率がだた下がる!)
・エミュレータの起動が遅すぎて、なんども再起動してしまった。 まさかあんなに(2分ぐらい?)待つとは。
・「エミュレータが1度起動した後は速い」とかよく見るけど、んなこたなぃ。そのために、IS01を買ってきてしまった(これは罠じゃないな)
・実機でもマニフェストにdebuggable="true"を入れると、FPSが2~3分の1になるイメージ。
・実機で1回停止させて、またすぐ実機の方でアプリを起動しても、まだPCがデバッグを掴んでいるような感じで遅いまま。 PCの方のデバッグのプロセス自体を落とす必要があるっぽい(じゃぁいつ勝手にプロセスは開放されるんだ・・・?)
まだまだあるけど、今日はこのへんで。
なんとか開発者登録の25ドルぐらいは回収したいなぁ。
ただそれだけなのだけど、とてつもなく罠があったのでここに書いておく。
・Eclipseの日本語化プラグインを入れると、なぜかビューの追加が出来ないようになったり、キーバインドが消えたりする(ctrl+tabでソースの切り替えが出来ないと開発効率がだた下がる!)
・エミュレータの起動が遅すぎて、なんども再起動してしまった。 まさかあんなに(2分ぐらい?)待つとは。
・「エミュレータが1度起動した後は速い」とかよく見るけど、んなこたなぃ。そのために、IS01を買ってきてしまった(これは罠じゃないな)
・実機でもマニフェストにdebuggable="true"を入れると、FPSが2~3分の1になるイメージ。
・実機で1回停止させて、またすぐ実機の方でアプリを起動しても、まだPCがデバッグを掴んでいるような感じで遅いまま。 PCの方のデバッグのプロセス自体を落とす必要があるっぽい(じゃぁいつ勝手にプロセスは開放されるんだ・・・?)
まだまだあるけど、今日はこのへんで。
なんとか開発者登録の25ドルぐらいは回収したいなぁ。
登録:
投稿 (Atom)