<   2015年 01月 ( 17 )   > この月の画像一覧

カメラのシーンモード

開発用メインとして使用していたs5110bより、KEIANタブレットの方がカメラのエフェクト数が多かったので、開発機に切り替える。

カラーエフェクトに関して言えば、

F-10D:4個
s5110b:3個
KEIAN:6個

と、ドコモ端末より良い。
カメラもバック、フロントで2個ついているし。

で、カラーエフェクトの次にシーンを使い始めたのだが。
(晴れ、曇り、夕方、人物とか、撮影シーンを設定できるアレ)

KEIANの、バックカメラが、シーン対応0ってどういうことだよ。
フロントカメラは、auto、night って2つも対応してるやんけ。
[PR]
by miries | 2015-01-31 01:51 | Android

カメラのsetColorEffectの不具合の解決策

朗報です。

Androidのカメラアプリで、カラーエフェクトを変更後、元に戻すために、"none"を指定しても無視される、そして、アプリを終了しても保持される、という不具合の解決策を発見しました。

どうやら、カメラのプレビュー映像のフォーマットを合わせて設定すると直るようです。
ざっとこんな感じで、場合分け。

openがブログのセキュリティ上ダメって言われたので、全角にしてます。


public void setColorEffect(String effect) {

if ( effect != null ) {

if ( effect.equals(Camera.Parameters.EFFECT_NONE) ) {// エフェクトなしに戻す

if ( MANUFACT_KEIAN ) {//▼ 恵安タブレット

Camera.Parameters params = mCamera.getParameters();
params.setColorEffect( effect );
mCamera.setParameters(params);
// 追加で映像フォーマットを指定
params.setPreviewFormat( ImageFormat.NV21 );
mCamera.setParameters(params);

} else if ( TerminalState.isManufacturer(ParamCamera.MANUFACT_S5110B) ) {//▼ s5110b

// 解放⇒生成で直る
mCamera.close();
mCamera.OPEN(getHolder());
mCamera.startPreview();

} else {//▼ 一般端末

Camera.Parameters params = mCamera.getParameters();
params.setColorEffect( effect );
mCamera.setParameters(params);

}

} else {// エフェクトあり

Camera.Parameters params = mCamera.getParameters();
params.setColorEffect( effect );
mCamera.setParameters(params);

}

}

}

[PR]
by miries | 2015-01-30 15:19 | Android

カメラのカラーエフェクトのバグ

Androidでカメラアプリを作っているわけだが、カラーエフェクトのバグが回避できなくて困っている。
(もしかしたら、ホワイトバランス等、他でもそうなのかも)

カラーエフェクトの設定は、
CameraParameters.setColorEffect(String);
この関数で行う。

Stringの部分に、"negative"を指定すれば、白黒反転、"sepia"でセピアカラーといった具合だ。
そして、"none" でエフェクト無しに戻せる。

…はずなのだが。

ドコモ端末F-10D:問題なし。

S5110b:エフェクトの切り替えはできるが、noneを指定すると無視される&プレビューが停止。
カメラを一度破棄することで、元に戻せる

KEIANタブレット:同じく、エフェクトの切り替えできるが、noneを無視。二度と復帰不可能

どれくらい不可能かといえば、カラーエフェクトを適用して、アプリ終了。内蔵されているカメラアプリを起動すると、さっき設定したエフェクトが残ったまま、というくらい、深く刻み込まれている。
再起動すれば元に戻るのだが…。


----
追記:

解決策見つけました。
http://miries.exblog.jp/24072856/
[PR]
by miries | 2015-01-29 15:38 | Android

続・Activity切り替え

カメラアプリには必須っぽいActivity切り替え。
そこにも、まだまだ罠が潜んでいた。

今自作しているアプリは、独自フレームワークを使っている。
Activityを継承したフレームワーククラスを作り、なるべく共通な要素をそこで処理し、
ゲーム毎に行うべき処理を、ゲームのメインクラスとして定義し、
フレームワークでインスタンスを生成している。

がActivityを継承したフレームワークは、そもそもActivity切り替えなぞ考えてない設計だった。
Activityを切り替えるたびに、この初期化部分が呼び出される。

レイアウトを作り変えるのが、切り替えの目的だから、毎回初期化部分が呼び出されないと困るわけだが、
その他の初期化部分は、なるべく一度しか処理されないようにしなければならない。

まあ、タッチライブラリの初期化、など、各種ユーティリティの初期化しか行ってないので、基本問題は無い。
と思いきや、ゲームクラスの初期化に問題があった。

シングルトン形式で、インスタンスを1つしか生成しないようにしているため、2回目以降の初期化(生成処理)は通過しない。
この初期化の中で、

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

これで、画面を横方向に固定している。
どちらの画面方向を使うかは、ゲームによって異なるので、フレームワークには入れなかった。

しかし、この処理は、毎回必要らしい。


初回起動・フレームワーク初期化、ゲームクラス初期化
 ↓
別のActivity切り替え
 ↓
元のActivityに戻る
 ↓
フレームワーク初期化・ゲームクラスはインスタンスがあるため、初期化スルー

とすると、画面設定が、任意方向可に戻るのだ。
面倒だのう。

あと、もう1つ。
これは、アプリ制作では、周知の事実だけど、Activity切り替え(View切り替え)を使うと、顕在化する。

AndroidOSにある、1つ戻るボタン(機能)。
これは、ホーム画面に戻る、ではなく、1つ前のVIEWに戻る、という機能なんだな。

ゲームで1つのVIEWしか使って無いと、ゲーム中に1つ戻ることで、ホーム画面に戻る。
が、Activity切り替えを導入し、一度切り替えると…。

1つ戻るボタンでは、永久に、アプリは終わらなくなる…。
[PR]
by miries | 2015-01-25 10:16 | Android

カメラとActivity切り替え

まだまだカメラアプリと格闘中。

中華タブレットから、F-10Dに戻ってアプリを起動すると…。
エラーの嵐!

なん…だと…。

ログ出力を見てみると、アプリ起動直後に、onDestroyが呼ばれ、その後、自動で再起動している。
そんなバカな。

以前は問題なく動いたはずだ。
何もなく Destroyが呼ばれるはずが無い。
改変の途中で、何かしらいけないことをやっているということか?

しかし、差分は大きい。探し出すのは不可能にちかい…。

いやまて。
通常、Destroyが呼ばれる=アプリ終了だ。
大抵、ぬるぽだったりするはずだ。

それが、そのままActivityが再起動するだと?
どこかでその現象みたことがあるぞ!

そう、画面の回転だ。
Androidは、画面が回転するだけで、Activityの破棄・生成が起きる。
しかし、それを回避するマニフェストは書いてある。

android:configChanges="orientation|keyboardHidden"

そう、これだ。
しかし、これと似たようなところに、原因があるはずだ!

…と目星をつけて、ぐぐると…見つけやしたぜ!

android:configChanges="orientation|screenSize|keyboardHidden"

なんと、APIレベル13以上から、orientation以外に、screenSizeもつける必要があるらしい。
そういえば、先日、API8⇒API16に上げたわ。

お 前 が 原 因 か!

つか、似たような原因じゃなくて、もろ回転じゃねーか!

ということで1つ解決したが、まだまだ残ってる。
IntentによるActivity切り替え後のカメラプレビューが表示されなかったり、
プレビューを開始すると落ちたりするのだ。

先は長い。
[PR]
by miries | 2015-01-23 23:33 | Android

続・Androidカメラアプリ

以前作ったカメラアプリを引き継いで、ブラッシュアップしているわけですが。

前回動作していたオートフォーカスが全然動作しないっすよ!
パーミッション許可していないとか、初歩的なミスはしていないっ!

…。
…。

そもそも、この中華タブレット(s5110b)に、オートフォーカス機能が無いだけだったorz

端末ごとに機能が違うから、こういうことが起こるんだわ。

オートフォーカスくらいデフォルト実装…ってのが思い込み。
起動時に、すべての端末機能を検出するように大幅修正。

カメラの個数も、複数の場合があるわけで、切り替えられるようにしなければならない。

そこで、ふと思う。

バックカメラとフロントカメラ、いまどきは、各1つずつくらいは搭載しているはず。
このカメラが、それぞれで対応プレビューサイズが異なった場合(正確には、アスペクト比が異なった場合)、やばいんじゃないの?

1つ前の記事で、画面サイズが微妙に変更になった場合は、プレビュー画像の対応をonMeasure()で計算したわけだが、カメラを切り替えても、Viewに関するイベントは何も発生しない。

今までは、ディスプレイサイズとサポートしているプレビューサイズから、使用するサイズを決定していたが、複数カメラに対応する場合、すべてのカメラでアスペクト比が変わらないように、選択する必要もありそうだ。

ちなみに、s5110bは、カメラを1つしか搭載していないので、もう1つのKEIANタブレットで調べてみると…。

176,144
240,160
320,240
352,288
640,480
640,480
320,240

対応サイズが7つって検出されるんですけど、下2つは、被ってませんかね。
いや、マジで、こういう red herring はやめて欲しいんですけど。
[PR]
by miries | 2015-01-23 14:42 | Android

カメラのプレビューとsurfaceViewのサイズ

カメラのプレビューサイズと、SurfaceViewのサイズについては、カメラアプリを作るときに必須なので、すでに多くのサイトで解説がなされているので、さらっとおさらい。

●カメラのプレビューサイズは、任意に決定できない。
サポートされているサイズセットの中から選ぶ

●プレビューサイズは、端末の画面サイズと同じとは限らない
(というか、一致しない方がデフォ)

●プレビューサイズを設定しても、最終的には、SurfaceViewのサイズになる。
(viewのサイズに、ViewGroup.LayoutParams.WRAP_CONTENTを指定した場合)

なので、16:9のアスペクト比を持つ画面いっぱいのViewに、4:3のプレビューを表示すると、横に伸びた映像になる。
この辺りを、どう解決するかで、みんながググる事になる。

一般的な解決方法は、SurfaceViewを作って、レイアウトにaddView() する際に、
プレビューの比率に合わせてサイズを指定することである。

しかしこのSurfaceViewのサイズ、一旦決めたら、変更するのがなかなか難しい。
もし、画面サイズが変わる端末があったら、プレビューが見切れたりしてしまう。

そんな、恐ろしい端末が、s5110bである!

b0163324_12252714.png
b0163324_12253662.png


画面下のアクションバーを(アプリ起動中でも)いつでも出し入れできるのだ。
アクションバーが消えているときは、画面一番下を横にスワイプすることで出てくる。

ちなみに画面サイズは、[800x480] [800x432]で、アクションバーの高さは48ピクセル、
割合にして、10%も変化してしまう。

アクションバーを出した状態で、カメラアプリを起動し、アクションバーを消すと、変な空白が生まれるわけだ。

この微妙な見た目に対応するためには、どうにかしてSurfaceViewのサイズを変更する必要がある。

画面サイズが変更されるので、onSizeChanged()が呼ばれるが、
名前の通り、サイズが変更"された"ときに呼ばれるメソッドだ。
ここで何をやっても何も起こらない。

そこで、見つけたのが、onMeasure() だ。

これは、画面サイズ変更時(だけではないが)に呼ばれ、
各Viewのサイズを算出して設定するメソッドだ。
ここで取得できるサイズは、変更後の新サイズで、試しに100x100を設定したら、きちんと反映された。

まあ、自力で算出しろってことだ。

そんなこんなで、実際のコード。
カメラプレビューは、アスペクト比4:3から変更するつもりがないので、固定で書き込んでいる。

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int widthMode= MeasureSpec.getMode(widthMeasureSpec);
int heightMode= MeasureSpec.getMode(heightMeasureSpec);

int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);

int dw = w;
int dh = h;

switch(widthMode) {
case MeasureSpec.EXACTLY:// 確定
break;
case MeasureSpec.UNSPECIFIED:// 自由
dw = h *4 /3;
break;
case MeasureSpec.AT_MOST:// 以下
dw = h *4 /3;
if ( dw > w ) {
dw = w;
}
break;
}
switch(heightMode) {
case MeasureSpec.EXACTLY:// 確定
break;
case MeasureSpec.UNSPECIFIED:// 自由
break;
case MeasureSpec.AT_MOST:// 以下
dh = dw *3 /4;
if ( dh > h )
dh = h;
break;
}

//サイズ反映
setMeasuredDimension(dw, dh);

}


[PR]
by miries | 2015-01-22 13:00 | Android

Intentによる、Activityの切り替え

カメラアプリを作っているのだが、定石として、SurfaceViewを2枚重ねる方法をとる。
1枚目は、カメラのプレビュー映像を表示、
2枚目は、カメラの操作や、画像フレームなどの表示、である。

ここまでは以前作っていたのだが、カメラアプリ単体として作っていた。
今は、ミニゲームの1つに、カメラを使うものがる、という体で作っているので、
ずっとカメラのプレビューsurfaceを出していくわけにもいかない。

が、プログラムの途中で、SurfaceViewを消したり、出したりなどのレイアウトにかかわる処理は、そう簡単にできないようになっている。

というわけで、これまたカメラアプリでは定石っぽい、Intentで、Activityを切り替える方法を使った。
通常アプリ用にレイアウトを組んだActivityと、カメラ用のレイアウトのActivityを切り替えるわけだ。

今回初めて使ったんだが、いや、面倒だわ(苦笑
Intentの切り替え自体は、めっちゃ楽にできるよ。でも、シーンのつなぎのほうがね…。

Activityのライフサイクルとして、onStartやOnPause、onResumeなどがいろいろあるが、
基本、onStopが呼ばれるまで動作している。

Intent切替を実行すると、次のActivityが起動して、onStart、onResumeなどが呼ばれるのだが、その後しばらくしてから、切り替え元の、onStopが呼ばれるのだ。

つまり、ある一定期間は、両方のスレッドが動いていることになる。
そのせいで、表示がぼろぼろに…。

というわけで、Intent切替を行うと同時に、切り替え元・先の両方で、一切何も表示せず、かつ、切り替え元が動作を停止するまで待機、という処理を入れてやったら、うまくいった。

…んだけど、Intentの切り替えに、たまに、5秒以上かかるときがあるんだよね。
速いときは1秒もかからないのに、この差はどこから出てくるのか。

なので、待機中のアイコンを出したいのだが…。
[PR]
by miries | 2015-01-21 14:56 | Android

Javaとフォント

「java タイピングゲーム テキスト フォント」で検索して来てくれた人がいたようで、
昔、たくさん作ってた身として、ちょっと気になる点を書いておこう。

フォントをテクスチャとして持っているのであれば、そんなに苦労しないと思うが、
システムフォントを使うと、ちと面倒。

クライアントの環境で動作するので、フォントの扱いがむずかしい。
とりあえずは、文字化けしない日本語フォントを探し出すのが最初のステップ。

端末の書体をピックアップするAPIと文字化けするかどうか調べるAPIがあるので、多分問題なくできると思う。

次の問題が、文字サイズ。
同じフォントサイズを指定しても、書体によっては、サイズが異なる場合がある。
また、プロポーショナルフォントの場合、文字幅が変わるので、ウインドウにぴったり入る文字数で区切る、とか、少々面倒なプログラムも必要になる。

あと、タイピングに必須なのが、今、どこまで表示しているか、というガイド。
書体になるべく影響されないようにするためには、文字列を2回描画すれば良い。

「あいうえお」と言う単語の、3文字目まで入力している状態なら、

「あいうえお」とグレーの文字を描き、全く同じ座標で、「あいう」という白い文字を書く。
文字列を区切ったり、連結したり…とかするよりは、このほうが早い。

この方法での問題点は、かな入力の扱い。
かな入力では、濁点もキー入力になること。
「がぎぐげご」という単語があったとして、最初に「か」を入力、その次に「゛」を入力してはじめて「が」になる。

なので、3文字目の途中の場合は、「がぎぐげご」の後に「がぎく」という文字を表示することで、表現することはできるのだが、濁点のあり/なしで、文字が大きく変わる書体とかあるんだなぁ、これが。

というわけで、書体を自由に切り替えることができる機能をつけることをオススメ。
[PR]
by miries | 2015-01-21 09:36 | デジタル系

イージングの実装

近年作ったプログラムパーツの中で、タイマーほど役に立ったものはないだろう。
まあ、大抵の人は、作っているんだけど…(苦笑

簡単にいうと、

Timer mTimer = new Timer(2.0);

と作成しておき、

float r = mTimer.getRate();

とすると、生成から2秒間で、0.0 ~ 1.0 まで自動的に変化する値が取得できるというもの。
(機種・環境によっては、自分で経過時間:elapsedTimeを加算することが必要)

少しつけ加えて、

Point pos = mTimer.getRate(startPos, endPos);

とすると、カーソルが開始座標から、目標座標まで動くようにできる。
この辺り、昔はラインアルゴリズムというのを使っていた。
ラインアルゴリズムの考案者(?)は、著書で、シューティングの敵弾の軌道にも使えると言っていが、実際には使えない。

もともとラインアルゴリズムは、
「開始座標から終了座標まで、一ドット幅のラインを隙間を空けずに描く」
というのが主旨で、その過程は考慮していないのだ。

で、タイマーは、どう考慮するのか、というと、経過時間による戻り値が、0.0~1.0である、というところに、イージングを設定できるのが素晴らしい。

イージングを使うと、移動にかかる時間は同じ2秒だが、最初ゆっくりで、後半速くなる、などの加速が使えるようになる。

b0163324_939992.png


イージングについては、いくつかの解説、および、ソースコードを載せているサイトがあるが、
大抵が、上記のようになっている。

:最初速くて、後半ゆっくり(OUT)
:最初ゆっくりで、後半速い(IN)
:最初と最後がゆっくり、中間が速い(IN-OUT)
()内は名称

ちなみに図にはないが、加速のない一定速度は(LINEAR)。

かける時間を、D
開始から現在の経過時間をTとすると、

LINEARは簡単で、
return T/D;

INは、
T /= D;
return T*T*T;


OUTは、
T /= D;
T = T-1;
return (T*T*T +1);

IN-OUTは、
T /= D/2;
if ( T<1 )
return 1.0f/2.0f *T*T*T;
T = T-2;
reurn 1.0f/2.0f *(T*T*T +2);


と書ける。
これは、解説サイトにあったソースコードを簡略化して使っているものだが、
イージングの強度の好みは、個人それぞれ違うと思う。

ただ、なぜかどの解説サイトも、これだけしか解説していないんだよな。
ゲームには、もう1種類必要なのだ。

b0163324_9512250.png

:最初と最後が速く、中間がゆっくり(OUT-IN)

これのコードがないので、作ってみた。

T /= d/2;
T = T -1;
return 1.0f/2.0f *(T*T*T+1);


ちなみに、実際のタイマーでは、これ以外にも、
三角関数の波形や、1.0~0.0になる逆数、連携用に常時0のまま or 1のままなんてのも実装している。
[PR]
by miries | 2015-01-20 09:56 | Android