socket.ioを最近勉強していて、こないだは簡単なチャットアプリを作ってみたので、今度は落書き共有アプリを作ってみました。perlin noiseも勉強してみたかったので、1次のperlin noiseで線を描くようにしてみました。使い方あってるか怪しいですが...。
こんな感じ
ソース
https://github.com/mitolog/AwkwardLineShare
※ SIOSocket.m/.hも少し改変したので、pod install後、個別に上書きしたら動くと思います
アプリの機能
- perlin noiseでいびつな線を描ける
- 線は一定期間で消える
- 描いた線をsocketをつないでいる各端末と共有できる
アプリの大まかな仕組み
- View ControllerのviewDidLoad()でソケット通信開始、及びタイマーでdrawRectを一定間隔で再描画するように各サブビューにsetNeedsDisplayを送る
- owner(自身)とmember(他端末)用のUIViewサブビュー(AwkwardLineView)を用意
- ownerの場合は、touchイベントをオーバーライドしてバッファ用の配列に座標を溜める
- memberの場合は、socket.ioのコールバックで座標の配列をもらい、バッファ用の配列と差し替える
- 各サブビューのdrawRectでバッファ配列に溜めた座標を使って描画処理
引っかかったところ
drawRectがsetNeedsDisplayで再描画されない!
これについては、別でまとめたのでそちらをご参照ください。
SIOSocketでクライアント側からemitする場合のパラメータは複数取れる
クライアント側ではこのようにemitしています
[self.socket emit:@"draw" args:@[points, self.socket.socketId]];
pointsの中身は @[@{x=1,y=0},@{x=1.1,y=0.1}...]
こんな感じで、CGPointのdictionaryの配列となっています。
self.socket.socketIdは、NSString、自身のsocketidになります。
で、これをSIOSocketのメソッドに渡すと、このように展開され、
objc_socket.emit('draw', [{"X":186.2593,"Y":82.25927}], 'KEW30FqD9rNAjdahAABL')
'draw'っていう名前のイベントとして、2つのパラメータを持ってサーバ側に送られます。
利用しているAPIは公式ドキュメントでいくとこれかなと。
Socket#emit(name:String[, …]):Socket
で、サーバ側では、こんな感じでキャッチできます。
socket.on('draw', function (data,socketId) {
io.emit('update', [data, socketId]);
});
});
つまり何がいいたいかというと、今まで、1つのパラメータしか取れないと思っていたんですね。。そのパラメータをjsonとかにして。でも複数とれるんだ、ということが今回分かりました。
サーバ側からemitする場合のパラメータは複数取れない?
ただ、サーバ側からemitする場合は、io.emit('update', [data, socketId]);
こんな感じで配列として渡さないとエラーになってしまいましたので、そこもご注意を。
SIOSocketで受け取る際は、
[self.socket on: @"update" callback: ^(SIOParameterArray *args)
{
// Update draw line data
[self updateDrawLineWithAry:args[0]];
}];
こんなふうに、args(配列)でラップされて渡ってきます。おそらくここもパラメータを複数取れるように配慮されて配列なんだと思いますが、なぜかサーバ側で1つしかパラメータをとれなかったので、args[0]
として1番目の要素に @[@[CGPointsのDictionary], 'ソケットid']
こういう感じの配列が渡ってくると思いますのでご注意を。
※ もしかしたらやり方がまずいだけで、サーバ側も複数のパラメータをとれるかもしれません。正しいやり方が分かる方いらっしゃればおしえてください!
参考
-
perlin noiseに関しては、Perlinノイズ(Perlin Noise)の1次元Perlinノイズの擬似コードっていう部分を参考にしました。
-
iOSでwebソケット通信する部分は、SIOSocketというライブラリを利用しました。
-
サーバ側の構築は前回のチャットアプリを作る記事を参考に