「WebSocketってなんだ?」「SocketRocketでiPhoneからWebSocket通信をする。」「Node.jsでWebSocketサーバを立てる」で要素技術は学んだので、さっそくリアルタイム通信なおもちゃの作成に挑みました。
みんなでボールを転がすだけの遊び
完成図がこちら!
画像なので分かりにくいですが、参加者ひとりひとりがボールを操作します。誰かがボールを動かすと、他の人のiPhoneにもリアルタイムに反映されます。それだけです。ここから、対戦要素を入れるなりなんなりすればリアルタイムなゲームなどが作れます。
WebSocketサーバへの接続を確立する。
ここは以前に書いたのと同じです。
- (IBAction)connect:(id)sender {
[hostTextField resignFirstResponder];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"ws://%@:8080/",hostTextField.text]];
socket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:url]];
socket.delegate = self;
[socket open];
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
}
画面を触った時に、その位置座標をサーバに送信する。
- (void)viewDidLoad
{
[super viewDidLoad];
worldImageView.delegate = self;
ballImageViews = [[NSMutableArray alloc] initWithCapacity:10];
}
- (void)touchesMoved:(CGPoint)location {
NSString *requestBody = [NSString stringWithFormat:@"{\"x\":\"%lf\",\"y\":\"%lf\"}", location.x, location.y];
[socket send:requestBody];
}
誰かがiPhoneの画像を触ると、その座標をサーバへ送信します。ImageViewはタッチされた時にコールバック処理が実行できるように拡張したものを使っています。
[socket send:requestBody];
ポイントはここです!事前にコネクションを確立したSRWebSocketのsendメソッドでサーバへデータを送信します。
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
[self touchesMoved:CGPointMake(100, 100)];
}
WebSocketのコネクションを確立した時にも、テキトーな座標を触ったのと同じ処理を実行することにしておきます。これで接続した直後に他にユーザーの画面にボールを出せます。
サーバからデータを受信したら描画する。
サーバから何かしらのデータが送られてきたら、それをトリガーに画面に書き換えを行います。
ここでポイントなのは、HTTP通信と違って、サーバからデータが送られてくるのは「自分が何かをした時だけではない」ということです。同時に参加している他のユーザーが操作した時にも、参加者全員へのデータ送信が行われるので、参加者全員の画面が再描画されます。
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
[self showBalls:[message JSONValue]];
}
ちなみに、次のブログで、サーバ側の実装を書こうとおもいますが、サーバからのレスポンスは、全てのユーザーの座標の配列になっています。ユーザーが3人参加していたら、サーバから座標が3つ入った配列が送られてくるイメージです。
それを以下のようにひとつずつ描画していきます。参加人数は随時変わるので、参加者数が増えた時はボールのUIImageViewを生成して追加します。
- (void)showBalls:(NSArray *)ballLocations{
while([ballImageViews count] < [ballLocations count]){
UIImageView *view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ball.png"]];
view.frame = CGRectMake(0, 0, 60, 60);
view.contentMode = UIViewContentModeScaleAspectFit;
[worldImageView addSubview:view];
[ballImageViews addObject:view];
}
for (int i = 0; i < [ballLocations count]; i++) {
NSDictionary *location = [ballLocations objectAtIndex:i];
UIImageView *view = [ballImageViews objectAtIndex:i];
CGRect frame = view.frame;
frame.origin.x = [[location objectForKey:@"x"] doubleValue];
frame.origin.y = [[location objectForKey:@"y"] doubleValue];
view.frame = frame;
}
これでクライアント側は完成です。あとは、サーバ側で、「誰かがボールを移動した時に、他の全員に、全員の座標をプッシュ通知する」というような処理を書けば良いです。
コメント
[…] Post navigation ← Previous […]