だいたい47度

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

無料iPhoneアプリゲーム ブレーメンのナンプレ

4x4のシンプルなナンバープレイスパズル。
マスをブレーメンの音楽隊でうめていきましょう。
問題数は200問以上。難易度も3レベルから選べます。
iOSsample1.pngiOSsample2.pngiOSsample3.png

基本無料ですが、むずいモードには有料ステージが60ステージあります。
一度購入していただくことで、それらのステージはずっと遊ぶことができます。

Privacy Policy
本アプリでは個人情報は収集されません。

NumberPlace Bremen

スポンサーサイト

PageTop

UIWebViewで位置情報alertが出る際の対応

ウェブビューでYahoo!とかを開いたときにポップアップが出てウザい件。
stack overflowに書いてあるとおりなんだけど。

- (void)webViewDidStartLoad:(UIWebView *)webView
{
[webView stringByEvaluatingJavaScriptFromString:@"window.alert=null;"];
}


UIWebViewDelegateのメソッドで [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; を書いたりするところですね。

PageTop

ARの基本と最も簡単なアプリ作成

ARに興味があったので調べてみました。

ARってなんなの?という部分を「AR入門[改訂版]―身近になった拡張現実」を参考に概略したあと、とっても簡単なiPhoneアプリを作って試してみます。



ARとは?
ARとは「拡張現実・強調現実」のことです。たまに聞く言葉ですね。
定義は「現実世界に何かしらの情報を追加し、現実世界の意味を拡張する」技術のことだそうです。うーん、定義として曖昧ですね。

Ronald T. Azumaという人が、もうちょっと詳しく定義しています。
1) Combines Real and Virtual (現実と仮想の融合)
2) Interactive in Real Time (リアルタイムな相互作用)
3) Registered in 3D (三次元位置合わせ)

この定義の場合、ちょっと領域は狭くなりますが、ARかどうかの判別には役に立ちそうです。



ARっぽいけど違うもの
以下の動画は、マッチムーブという技術を使って作られているものです。
現実世界にロボットが描画されていてすごいですね!カメラの揺れにあわせてきちんとロボットが描画されているので違和感がありません。

マッチムーブという技術は「映像からカメラの位置を計算し、3次元空間を計算した上で、CGを描画する」技術です。
そのため、ARではないのです。「1) 現実と仮想の融合」と「3) 三次元位置合わせ」は行われていますが、「2) リアルタイムな相互作用」が行われていないのです。



ARの例
幾つかARの例を見てみましょう。

いま一番有名なのはGoogle Glassではないでしょうか。


他に面白い例として、米軍が保守作業にARを使っていたようです。作業手順が明確に描画されるのでミスも減りそうですね。


BtoC的なサービスとしては試着ARが面白いです。他にも、腕時計の試着AR、メガネの試着ARサービスや、配送したいものをWebカメラに写すと小包の大きさを計測してくれるサービスなどがあるようです。


直近で面白かったのは塗り絵をすると動くARアプリ。これはすごい!




ARの位置あわせ
ARは、位置合わせ(Registration)が急所となります。きちんと現実世界にリンクしないと、それっぽく見えません。

その位置合わせ方法ですが、大きく2種類あります。
1) 画像を分析して位置合わせ
2) センサを使って位置合わせ



画像を分析して位置あわせ
「1) 画像を分析して位置合わせ」については幾つか方法があるので、それらを映像で見てみます。「2) センサを使って位置合わせ」については簡単なiPhoneアプリを作ってみましょう。

「1) 画像を分析して位置合わせ」については、更に以下の3通りの方法があります。
1-1) 専用マーカを使う方法
1-2) 特定画像マーカを使う方法
1-3) マーカレス(PTAMM)

まず「1-1) 専用マーカを使う方法」ですが、マーカとなるものを現実世界に配置し、それをカメラで捉えることで場所や傾きを計算、描画する方法です。たとえばNintendo 3DSのARはとても面白いものです。
この方法は他の方法に比べて計算量が少なくすみますが、暗かったり遠かったりとマーカの視認性が悪いと問題を生じます。また、マーカがある事自体が許されない環境もあるかもしれません。


次に「1-2) 特定画像マーカを使う方法」ですが、これは専用マーカの代わりに汎用的なマーカを使うものです。顔認識や手認識の技術は進んでいるので、顔認識してお面をつけるARなどがあげられます。専用マーカより汎用性が高い分、画像認識の計算量は増えます。


最後に「1-3) マーカレス(PTAMM)」。これはマーカを使いません。ではどうするかというと、一番最初にカメラで周りを撮影し、3D空間を認識させた後にそこにARを計算させて投影させるものです。マーカが要らないことは大きなメリットですが、計算が難しく、また認識しやすい空間を選ばなくてはいけない点が微妙です。




センサを使って位置あわせ
この方式のARをとしてはセカイカメラなどが有名ですね。

センサを使って位置合わせをするARは流行りつつあります。スマホがカメラに加え、いろんなセンサを持つようになったので、多くのことが試せるようになっているためです。ざっとあげても、GPS・電子コンパス・加速度センサ・ジャイロセンサ・磁気センサ。iOS4からはCoreMotionフレームワークが使用可能となっており、それを使って様々なセンサを簡単に使用することができます。

ここでは、iPhoneの傾きを感知して画像の描画を変更してみます。その結果「iPhoneの中心位置が固定されている」前提の元で、iPhoneがどの傾きになっても一定の位置に画像が描画されている状況をARで実現させます。UQTimes様と実践! iPhoneアプリ開発 26-28回を参考にさせてもらいました。

まずは傾き感知をただするだけのアプリを作ってみましょう。Viewの上に3つのUILabelを並べ、それらのLabelにRoll, Pitch, Yawを描画します。Roll, Pitch, Yawについてはオイラー角で調べてください(先に実際に触ったほうがわかるかもしれません)。

XCodeの「Linked Frameworks and Libraries」でCoreMotionフレームワークを追加した後、ViewControllerのプロパティとしてCMMotionManagerを持たせ、viewDidLoadなどでインスタンスを作成させます。デバイスがモーション感知可能かどうかのif文を追加します。

_motionManager = [[CMMotionManager alloc] init];

if (_motionManager.deviceMotionAvailable) {
}


if文の中では、CMMotionManagerの更新間隔、更新する時の処理、更新開始の3つを記述します。

// 更新間隔
_motionManager.deviceMotionUpdateInterval = 1.0f / 60.0f;

// 呼び出されるハンドラ
CMDeviceMotionHandler deviceMotionHandler;
deviceMotionHandler = ^ (CMDeviceMotion* motion, NSError* error) {
};

// 更新開始
[_motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler:deviceMotionHandler];


で、最後にハンドラの中身を実装します。

// デバイスの向きを表示する
self.rollLabel.text = [NSString stringWithFormat:@"ROLL:%.1f", motion.attitude.roll];
self.pitchLabel.text = [NSString stringWithFormat:@"PITCH:%.1f", motion.attitude.pitch];
self.yawLabel.text = [NSString stringWithFormat:@"YAW:%.1f", motion.attitude.yaw];


これで1/60ごとに感知された傾きがLabelに描画されるはずです。実機でテストしてみると、画面を上に向けた状態でiPhoneを机の上に静置すると全てを0にできるような感じがします。

ここまで出来れば、あとはカメラ上にUIImageVIewを貼っつけ、それの描画位置を変えるだけです。カメラへの画像描画はこちらをご参照下さい。

画像位置の変更は、ハンドラの中に以下の感じで書きます。単純にオイラー角のタンジェントをとるだけで位置調整ができています。

float imageHeight = 500;
CGSize screenSize = [UIScreen mainScreen].bounds.size;
float x = tanf(motion.attitude.roll) * imageHeight + screenSize.width / 2;
float y = tanf(motion.attitude.pitch) * imageHeight + screenSize.height / 2;
_arImageView.center = CGPointMake(x, y);
_arImageView.transform = CGAffineTransformMakeRotation(motion.attitude.yaw);


これを実機でためしてみると、おぉ結構それっぽい動きをします。このあとは、iPhoneの縦横移動の感知対応や、画像の3D的な傾きの対応、2D画像を3D画像に変えるなどをやっていくと、更に楽しめそうですね。

ということで今回は長かったけど、これまで。

AR入門[改訂版]―身近になった拡張現実 (I/O BOOKS)AR入門[改訂版]―身近になった拡張現実 (I/O BOOKS)
(2013/05/16)
佐野 彰

商品詳細を見る

PageTop

UITabBarControllerのハマリどころとシステムアイコン

UITabControllerはiOSのタブ機能を実装してくれているコンポーネントです。その子クラスを作った際に迷ったところをメモ。※ARC対応コードです。

基本的な使い方
UITabBarControllerの子クラス"MyTabBarController"を作ってみました。

MyTabBarControllerのタブごとに描画するUIViewControllerは別に作る必要があります。以下では"MyViewController"という独自ViewControllerを3つ、タブとして使っています。

MyViewControllerは引数を受けて別々の描画を行います。以下では引数をNSString *としています。それぞれの引数は、MyTabBarControllerのプロパティにNSArrayとして受けます。

つまり、MyTabBarControllerのインスタンスを生成した後、tabItemsプロパティに描画したいタブの数だけパラメータを渡せば、うまいことMyViewControllerをタブとして描画してくれるようになっています。

// MyTabBarController.h
#import <UIKit/UIKit.h>
@interface MyTabBarController : UITabBarController
@property (nonatomic, strong) NSArray * tabItems;
@end

// MyTabBarController.m
#import "MyTabBarController.h"
@implementation MyTabBarController : UITabBarController

- (void)viewWillAppear:(BOOL)animated
  // MyViewControllerのArray
  NSMutableArray *controllerArray = [NSMutableArray arrayWithCapacity:[tabItems count]];

  for (int i = 0; i < [tabItems count]; i++) {
    NSString *param = [self.tabItems objectAtIndex:i];

    // パラメータを使ってinitします。普通にinitしてからpropertyに渡しても可
    MyViewController *controller = [[MyViewController alloc] initWithParam:param];
    [controllerArray addObject:controller];
  }

  [self setViewControllers:controllerArray];

  [super viewWillAppear:animated];
}
@end

// 使い方例
MyTabBarController * myTabBarController;
myTabBarController = [[MyTabBarController alloc] init];
myTabBarController.tabItems = @[ @"hoge", @"fuga", @"hogefuga"];


ここでハマったのが、「カスタムのUITabBarControllerではviewDidLoadが想定しない時点で呼び出される」という点でした。上記でviewWillAppear:内に書いてある処理は、最初はviewDidLoad内に書いていたのですが、何度やっても描画がうまくいきません。

調べていく内に、どうもUITabBarControllerのinitメソッドにおいてviewDidLoadが呼び出されているようでした。そのため、呼び出し側の[[MyTabBarController alloc] init];時点でviewDidLoadが実行され、その後でpropertyに値を渡す形になってしまっていたのです。

非常に気持ち悪いのですが、viewWillAppear:に書くことで対応しました。

システムアイコン一覧
UITabBarControllerのタブに描画するアイコンは幾つか用意されています。12のenumの数だけあるようですが、画像一覧が見つからなかったので貼っておきます。

systemicons.png
UITabBarSystemItemMore, UITabBarSystemItemFavorites, UITabBarSystemItemFeatured, UITabBarSystemItemTopRated
UITabBarSystemItemRecents, UITabBarSystemItemContacts, UITabBarSystemItemHistory, UITabBarSystemItemBookmarks
UITabBarSystemItemSearch, UITabBarSystemItemDownloads, UITabBarSystemItemMostRecent, UITabBarSystemItemMostViewed

PageTop

【Objective-C】Restkitなどでのアカウントのログアウトでハマった

アカウント登録型のiOSアプリを作っていたのですが、ログアウト周りでハマりました。

Aさんでログインしたあと、ログアウトし、Bさんでログインして情報をサーバから受け取ろうとすると、なぜかAさんの結果が帰って来てしまうというバグがどうしても取れなかったのです。なお通信はBASIC認証を使って行なっています。

まずサーバ側に問題がないか確認しました。コマンドラインからサーバ問い合わせをすると、アカウントごとにちゃんと違う結果が返ってきます。またwiresharkを使って通信をみていると、どうもアプリから発信している要求がおかしいことがわかりました。

しかし、アプリ側でログ出力させてみても、きちんと違うクエリを発行しているように見えます。AFNetworkingを使用していたのですが、setAuthorizationHeaderWithUsername:password:がきちんと呼ばれていますし、その後の交信でも使われていそうです。

すわキャッシュか!と思い、ログアウトのときに大いにキャッシュ削除を記述してみましたが、うまくいきません。以下のように念入りにCookieも消していますが、うまくいきません。

NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];

if ([credentialsDict count] > 0) {
NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
id urlProtectionSpace;

while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
id userName;

while (userName = [userNameEnumerator nextObject]) {
NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userName];
[[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
}
}
}

[[NSURLCache sharedURLCache] removeAllCachedResponses];

NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];

id cookie;
for (cookie in cookies) {
[cookieStorage deleteCookie:cookie];
}


他にもセッションのAuthorizationを書き換えてみたり、と色々やってみましたが全然ダメでした。

困り果てた結果、以下のブログに行き着きました。
HTTP Basic Authentication "Logout" with NSURLConnection
http://www.springenwerk.com/2008/11/i-am-currently-building-iphone.html

なんとURLの一番最後に#をつけることでキャッシュさせなくするという方法。

[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:3000/something.json"]]

[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:3000/something.json#"]]


で、これでやってみると確かにうまくいく!

2日ほどここで困っていたのですが解消しました。特にRestkitとCoreDataの導入を試しでやっていたときだったので、問題がNSURLConnectionにあるという切り分けにも手間取りました。なお、パラメータをつけるときは、URLの一番最後に#がくるようにうまく調整しないといけないので注意してください。

PageTop
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。