頭と尻尾はくれてやる!

iOSアプリなどの開発日記です


iPhone/iPadの画面をReflectorでMacへ

普段iPhoneのデモ動画なんかを録画するのは基本的に
kishikawakatsumi/ScreenRecorder · GitHub
を使ってるんだけど、iPadの画面を録画しようとしたら落ちてしまう。コードを見てみたけど俺の力量ではどこが悪いのかもわからず、、、どうしたものかな、と思って困っていたらこんなのを見つけたんだよ。

Reflector - AirPlay mirror your iPhone or iPad to any Mac or PC

AirPlayを使ってMacのディスプレイにミラーリングしちゃうというとんでもないアプリだ。

まずMacでこのReflectorを起動しておく。

iPhoneスクショ

↑iPhoneの下側から引っ張りだせるコントロールセンターという画面(上図左)でAirPlayの部分をタップしたら上図右のような画面が出るので自分のMacの名前を選択、ミラーリングする。これだけ。

Macスクショ

↑こんな感じでMacでみることができて、しかも録画も可能!
AppleTVでのミラーリングと変わらない手順で同じようにMacの画面に表示できるなんてあまりにも簡単。
iPadの画面を録画してYouTubeにアップしたのはこちら→頭と尻尾はくれてやる! / SpriteKitの2D物理エンジンで自動車っぽい動き

かなり感動したので購入を考えた(上記の内容は無料のトライアル版で時間制限あり)んだけどもうすぐOS X変わるので、Mavericks‎でも動くのを確認したら購入しようかな。


拡大したビューに乗ってるビューをドラッグしたい

iPhone/iPadアプリだと二本の指でぐにゅーんと画像なんかを拡大/縮小することができるのがあるよね。これはUIScrollViewを使えば実現できるんだけど、拡大/縮小する画像の上に別なビューがあってそれをドラッグしたいって場合はどうすればいいんだろう?ってお話。

頭と尻尾はくれてやる! / UIViewオブジェクトをドラッグする
↑ビューのドラッグはこんな感じでやる。

拡大はUIScrollViewDelegateの
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
メソッドで対象のオブジェクトを指定する(いつもながらこれ便利だよねえと感心しちゃうよ)。

ビューの構成はこんな感じで。
self.view
 |
 - scrollView ( UIScrollView )
   |
   - sheet ( UIView )
     |
     - imageView ( UIImageView )
     - circleView ( UIView )

上のUIScrollViewDelegateメソッドで拡大するビューを指定するのにsheetってビューを用意しといて、その上に拡大して見たい画像とドラッグ可能なcircleViewってのを乗せてる。

viewController内での処理は以下のような感じに。いろいろとはしょってるけど。
{
    //scrollView
    scrollView = [[[UIScrollView alloc] initWithFrame:(CGRect){0,0,width,height}] autorelease];
    scrollView.delegate = self;
    scrollView.minimumZoomScale = 1.f;
    scrollView.maximumZoomScale = 12.0f;
    [self.view addSubview:scrollView];

    //乗せるためのビュー
    sheet = [[[UIView alloc] initWithFrame:scrollView.bounds] autorelease];
    [scrollView addSubview:sheet];

    //画像
    UIImageView *imageView = [MyImageUtility makeImageViewForFileName:@"sasaki.png"];
    imageView.frame = (CGRect){0,0,320,imageView.height*320.f/imageView.width};
    [sheet addSubview:imageView];
        
    //サイズ指定
    sheet.frame = (CGRect){0,0, imageView.width , imageView.height };
    scrollView.contentSize = (CGSize){ imageView.width , imageView.height };

    //ドラッグするビュー
    UIView *circleView = [[[MyCircleView alloc] initWithRadius:30.f color:color center:] autorelease];
    [sheet addSubview:circleView];
    [MyGestureUtility setDragForView:circleView];
}

#pragma mark UIScrollViewDelegate method
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)aScrollView
{
    return sheet;
}
最初上のようにしてたんだけど、いざ使ってみると問題が発生。
拡大する前だと円(circleView)はドラッグできるんだけど、拡大した後だと円はドラッグできずにscrollViewが動いちゃうんだよ。

拡大時にドラッグできない!のスクショ

↑拡大するとドラッグできない!の図(これだけじゃわかんないよね)。

偶然発見した解決方法は左手の二本指で画像を押さえて、右手の指一本でドラッグする、というモノ。いや、そんなのいつ使えなくなるかわからないし、使いにくいったらありゃしない。レビューで★一つが並ぶのが目に見えてる。

どうしたものかなあと思って、ふと手持ちのお絵描きアプリはどうなってるんだろうといじってみたところ、scrollViewの移動は指二本でやってることに気が付いたよ。指二本で移動させて、指一本だと線が描けるって仕様。
なるほど〜!そうやって区別していたのか!

どうやって実装すればいいのかな?と思いつつ何かそれ用のがあるんじゃない?と思ってリファレンスを眺めたら、、、ちゃんとあるじゃない!
scrollView.panGestureRecognizer.minimumNumberOfTouches = 2;
↑これを追加すればいいだけ!
これで移動(パン)は指二本でやるんだぜって設定になる。素晴らしい!

拡大時にドラッグできた!のスクショ

↑ほら!ドラッグできた!の図(ご、ごめんなさい)。


SpriteKitの2D物理エンジンで自動車っぽい動き

iOS 7で登場したSpriteKitにはBox2Dのような物理エンジンがあるので、物体が衝突した時の挙動なんかも計算してくれるよね。
これを使って自動車を上から見た時の動きをシミュレートするにはどうしたらいいんだろうってお話。
横じゃなくて上から見た場合ね。

1) Before
単純に前輪部分でステアリングの角度を考慮した力を与えるだけだと、、、



↑とてもじゃないけど車に見えない。ハンドルをきったりぶつかったりすると簡単に回転してしまうんだけど、これっておかしいじゃない。自動車は四輪で地面と接していてタイヤの方向以外へは簡単には行かないはずだよね。


2) After



まだ完璧とは言えないけど少しマシになったかな?主に下の二つをやってみたのよ。
1)angularDampingプロパティを設定する
2)タイヤの左右方向への速度を小さくする

1)SpriteKitのSKPhysicsBodyクラスのangularDampingプロパティをいじっていなかった(デフォルトは0.1)ので、必要以上に回転していたみたい。これを大きくするだけでも車っぽくなる。

2)でも1)だけだとドリフトがそれっぽくならないし、回転の中心は図形の重心になるのでやっぱりよくみると車の挙動とは違うんだよね。
実際の車の挙動を考慮して、タイヤに相当する部分が横方向には拘束される、というのを物理エンジンで表現しようとしたんだよ。

モデル化

↑動画では車体の部分に画像を適用してるけど、物理エンジンで考慮する物体は車体の前後のタイヤ二つの合計三つでモデル化してる(濃い赤が前輪)。車体とタイヤはSKPhysicsJointPinでジョイント設定。
SKPhysicsBodyにはvelocityってプロパティがあってこれで速度を与えることができるのでこれを使うよ。自分で速度を決めるなんて物理エンジンどこ行った?って感じだけど、まあ仕方ない。

速度の成分

↑横方向の速度を調整。SKSceneの回転方向はどっちがプラスよ?とか何かと面倒だったりする。

横方向を完全にゼロにしちゃうとドリフトしてくれない。それも寂しいのでスピードを出し過ぎてたら滑って欲しかったりする。
それを考慮してしきい値を超えない場合は横方向の速度はゼロ、超えた場合は係数(<1.0)を掛けるようにしてみた。

いろんなパラメータのバランスの取り方が難しい、けどこういう処理で少しは車に近づけたかな。

ちなみに車を走行させてるのはiPad上で、車のハンドル操作はMultipeerConnectivityを使ってiPhoneをハンドル代わりにしてる。左上の数字はハンドル用iPhone側から受信したCoreMotionで得た値。


YouTubeの動画を縦長でブログに埋め込む

最近YouTubeにiOS 7のデモ動画なんかをアップしてるんだけど、iPhoneで撮影すると基本縦長になるじゃない。いや、もちろん横向きに撮影してもいいんだけど、基本は縦長だよね。
それをYouTubeにアップすると、こんな感じで横長のスクリーンに両サイド黒い部分がたくさんでちゃう。

YouTubeのスクリーンショット1

なんとも残念な感じがするけど、これをブログに引用する時、縦長にできることを知ったんだよ。
頭と尻尾はくれてやる! / SpriteKitの物理エンジン使ってみた
↑この記事内だと両サイドの黒い部分はないよね。

不思議なことに特に設定はなくても、単にタグ内の数字を変えるだけでいいのよ。

YouTubeのスクリーンショット2

↑動画の下の方にある
共有/埋め込みコード
の部分でタグを取得できるでしょ。
このタグ内の数字を
width="320" height="568"
とかにするだけ。もちろんこのサイズは4インチディスプレイの場合の画面サイズ。少し大きいかなと思えば比率を同じにして値を少なくすればOK。

これを知ってからは無理に横向きで動画を作成しなくなったよ。


iOS 7のMultipeerConnectivityでストリーミングしてみた

iOS 7でMultipeerConnectivityってのがでてるじゃない?あれ試してみたんだよ。

今までだとGameKit frameworkのGKSessionとか使ってデバイス間でのやりとりしていたんだけど、あれに代わるようなモノと理解すればいいのかな?
どうしてこう似たようなのが出てきたのかよくわからないんだけど、、、確かに便利になったんだ。

というのもGKSessionあたりを使ってデータを送受信する時には1000バイトを超えるとよろしくない(リファレンスにはそういう記述があって、超えたからといって落ちるわけでもないけど)ってことなので、画像なんかを送受信する場合はデータを分割して何度も行ったり来たり、、、ってのを管理するためにゴリゴリとクラスをたくさん作って頑張ってコード書いてたんだよ。

そこへMultipeerConnectivity frameworkだよ。

これを使うと画像の送受信も簡単にできた。
それどころか片方のデバイスのカメラで取得した画像をストリーミングでもう片方のデバイスに表示させる、なんてのも簡単にできた。実はストリーミングなんてサーバーとか必要で、iPhone同士なんかでもできるなんて知らなかったよ。



↑実際にやってみたらこんな感じ。
iPod touch (第五世代)のカメラに写る画像をどんどんiPhone 4Sへストリーミングで送ってる。上の動画はその受信側の画面を撮影したもの。
送受信する一枚の画像のサイズは100x100のRGB、 unsigned char(1バイト)なので30000バイト。
見ての通りスピードが出ないのでよくあるリモートカメラアプリとしては「すげえ!さすがiOS 7だ!」って感じにはならなかったな。
それでも作りやすさからいうと開発者にはありがたいね。
当然俺コードはゴミ箱行きだよ。あれ、目から熱いものが、、、




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.