Your SlideShare is downloading. ×
  • Like
node+socket.io+enchant.jsでチャットゲーを作る
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

node+socket.io+enchant.jsでチャットゲーを作る

  • 15,506 views
Published

 

Published in Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
15,506
On SlideShare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
57
Comments
0
Likes
25

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. node+websocket+enchant.js で2時間でピグみたいなチャットゲーを作る! 2012/2/11 長野ソフトウェア技術者グループ NSEG 第 24 回 勉強会 有限会社ジーワークス 佐藤 潔
  • 2. 今日やることの概要まずは実際につないで遊んでみてください http://hakuba.jp:20105/
  • 3. 書いたコードはこれだけクライアント→サーバ↓
  • 4. Node● サーバサイド javascript● イベントドリブン● シングルスレッド● C10K(1 万クライアント ) 問題に対応● javascript は遅そう? → javascript は今や遅くない
  • 5. websocket● はやりの HTML5 な技術● http 上で VPN 張るイメージ● socket.io というフレームワークが超優れもの → websocket 非対応のクライアント上でも同 じ API で通信できる
  • 6. enchant.js● javascript のゲームフレームワーク● 日本の会社(ユビキタスエンターテイメント)製● ベーマガ世代な人には特にぐっとくるポリシー
  • 7. この構成にしたわけ● 今回は C10K とかは全然関係ない● node+socket.io ですごく簡単にリアルタイム 通信アプリが書けるから● enchant.js の RPG っぽいサンプルを流用す ることで遊べるものが簡単に作れる
  • 8. 環境構築学習用サンプルソースの URLhttps://github.com/stealthinu/enchat/zipball/masterGit のリポジトリはgit@github.com:stealthinu/enchat.git
  • 9. Linux/MacOS の方は自前のノートへ インストールパッケージを利用する場合Installing Node.js via package managerhttps://github.com/joyent/node/wiki/Installing-Node.js-via-package-managerDebian / Ubuntu / Cent / OS X などメジャーなのはだいたいある
  • 10. 手で入れる場合自分が Ubuntu-10.04-LTS での例「 libssl-dev 」と npm のインストールで必要な「 curl 」を入れとく> sudo aptitude install libssl-dev curlnode.js 本体のインストール> wget http://nodejs.org/dist/v0.6.10/node-v0.6.10.tar.gz> tar -zxf node-v0.4.8.tar.gz> cd node-v0.4.8.tar.gz> ./configure> make> sudo make install
  • 11. パッケージマネージャ npm のインストール自分は root になってないとうまく入らなかった。しかし sudo でやんのは推奨ではないらしい。が他の方法もなんかどうしたもんか、という感じだったのでこれでいく。> sudo -s# curl http://npmjs.org/install.sh | shnpm の使い方はこんな感じ> npm install express> npm install socket.io
  • 12. nvm も使ったほうがよいnode はアップデートが非常に早くどんどん進化していってるため、新しいバージョンでは動かないということもちょくちょく起こる。そこで nvm という、バージョンを切り替えて使うためのものツールも利用すると良い。
  • 13. Windows の方僕のノートにアカウントと Cloud9IDE を準備してありますCloud9IDE とは→ node で動く javascript で書かれた統合開発環境 ブラウザ上でばしばし動く  Cloud9 という同じ名前で PaaS もあるよ  http://c9.io/
  • 14. 使い方twitter のアカウント名とパスワードでログイン~/cloud9/config.js の port を確認ユーザ認証ないので今回はポートで分けるため注意!Cloud9 IDE を起動> cd ~/cloud9> bin/cloud9.sh -l 192.168.x.x -w workspaceブラウザでアクセス http://192.168.x.x:xxx
  • 15. node でチャットを作るnode で簡単なチャットを作ることを目標に進めます● まず適当に node とかフォルダ作る● サンプルファイルを落として参照ようとして展開する● 出来上がりサンプルは ex? という名前で作ってあります● 同じファイルをどんどん追記修正していく方針でいきます● git とかの利用は各自適当に
  • 16. コンソールに "Hello World!" を表示コンソールに表示するにはほんとに 1 行だけ。これくらいなら include とか require とか全く不要--- ex1.jsconsole.log("Hello World!");---enchat.js というファイルをエディタで作りますCloud9 IDE の人はFile->new->JavaScrip file->"enchat.js"
  • 17. 実行するには> node enchat.jsCloud9 IDE では、上のボタン「 run 」押すと configurationのウィンドウが開く。Name:chat JavaScript file:enchat.jsとなってりゃ OK なのでこれで「 Run 」押す。下の「 Output 」にHello World!が表示される!
  • 18. http サーバを作って "Hello Wold!"次は http サーバを作ってブラウザ上に Hello World します。基本的には http のライブラリを呼んで設定をしてやるだけ。--- ex2.jsvar sys = require( sys );var HTTP = require( http );var server = http.createServer( function http_createServer( request, response ) { response.writeHead( 200, { content-type: text/plain } ); response.write( "Hello World!" ); response.end(); }).listen(20005);console.log("Server started.");---http://192.168.x.x:xxxx を開いてみます。
  • 19. express を使ってもっとお手軽にexpress というフレームワークを使うともっと簡単に。まず npm という node.js のパッケージマネージャを使って「 express 」をインストール。> npm install expressこれで express がインストールされます。--- ex3.jsvar app = require( express ).createServer();app.get( /, function( req, res ) { res.send( Hello World! );});app.listen(20005);console.log("Server started.");---こりゃ簡潔!
  • 20. express で Web サーバを作ってみるexpress を使うとものすごく簡単に Web サーバを作ることが出来ます。実は express が全部やってくれるので、公開するフォルダをどこにするかを設定するだけ。--- ex4.jsvar express = require( express );var app = express.createServer();app.configure( function() { app.use( express.static( __dirname + /public ) );});app.listen( 300x );console.log( "Server started." );---ほぼなんもしてないですね。"public" というフォルダを作り、その下に適当に "index.html" とかを作ってアクセスしてみましょう。
  • 21. websocket でメッセージを送って表示ここまではつまらなかったですがやっと本題の websocket に入ります。node では簡単に websocket 等を使ったリアルタイム通信を行うための socket.io というフレームワークが利用できます。これを使ってクライアントにメッセージを送ってみます。まずは WebSocket を使うためのパッケージ「 socket.io 」をインストールします。> npm install socket.io
  • 22. websocket でメッセージを送って表示 (2) 今回はサーバ側とクライアント側どちらも、また最初に開く HTML も必要になります。 html とクライアント用 js は public 以下に index.html と chat.js などの名前で作成。 --- ex5.html message: <div id="message"></div> <script type="text/javascript" src="ex5c.js"></script> --- ex5c.js socket.on("connect", function() { socket.emit("message", "Hello server!"); }); socket.on("message", function(text) { $("#message").html(text); }); --- ex5.js io.sockets.on("connection", function(socket) { console.log("connect new client."); socket.emit("message", "Hello client!"); // 繋がったらとりあえず送る // こちらがメッセージを受けた時の処理 socket.on("message", function(text) { console.log("message:" + text); }); }); ---
  • 23. websocket でメッセージを送って表示 (3)サーバ側のソースでio.sockets.on("connection", function(socket) { …の中にソケットに接続があったときにどういう動きをするか記述します。そして同じような記述でsocket.on("message" function(text) { …の中には「 message 」というタグで通信を受けた時の動きを記述します。
  • 24. websocket でメッセージを送って表示 (4)クライアントも似ていますが、接続されることが無いためsocket.on("connect", function() { …に接続が出来た時の記述をsocket.on("message" function(text) { …にサーバと同じく「 message 」というタグでメッセージを受けた時の動きを記述します。socket.emit("message", text)で「 message 」というタグを付けて text の内容を送信してします。$("#message").html(text);でクライアントでメッセージを受け取ったら jquery を利用して中身を書き換えています。ブラウザに「 Hello client! 」が表示されサーバコンソールに「 Hello server! 」が表示されます。また、複数の接続も可能なことも確認してみてください。
  • 25. broadcast を使って全員と通信このままだとサーバとクライアントが 1 体 1 でしか通信できないので複数の接続への送信を行います。そのためには broadcast を使います。--- ex6.html message: <div id="message"></div> <input id="message_text" type="text"> <input id="message_button" type="button" value="send"> <script type="text/javascript" src="ex6c.js"></script>--- ex6c.jssocket.on("message", function(text) { $("#message").html(text);});$("#message_button").click(function() { var message = $("#message_text").val(); socket.emit("message", message);});
  • 26. broadcast を使って全員と通信 (2)--- ex6.jsio.sockets.on("connection", function(socket) { console.log("connect new client."); socket.emit("message", "Hello client!"); // 繋がったらとりあえず送る socket.broadcast.emit("message", "new client login!"); // 全員に知らせる // こちらがメッセージを受けた時の処理 socket.on("message", function(text) { console.log("message:" + text); socket.broadcast.emit("message", text); }); // 切断した時の処理 socket.on("disconnect", function() { console.log("disconnect."); socket.broadcast.emit("message", "client logout."); });});---broadcast はたぶんすぐわかるでしょう。ついでに切断した時の処理と$("#message_button").click(function() { …で jquery を使って送信ボタンを押したときに emit 掛けるように追加しています。☆ 出来た人は、自分の発言も表示されるように修正してみましょう。
  • 27. ログイン時に名前を送って表示なんてことないようですが、ここでクロージャの概念が出てきます。あと、メッセージについてるタグ毎にイベントを変更出来ることを確認して下さい。--- ex7c.jsname = prompt("Input name:");socket.on("connect", function() { socket.emit("name", name);});socket.on("name", function(text) { $("#message").html($("#message").html() + "<br>" + "login:" + text);});
  • 28. ログイン時に名前を送って表示 (2)--- ex7.js // 名前を送ってきた時の処理 var login_name = "unknown"; socket.on("name", function(text) { console.log("name: " + text); login_name = text; socket.broadcast.emit("name", login_name); }); // こちらがメッセージを受けた時の処理 socket.on("message", function(text) { console.log("message:" + text); socket.broadcast.emit("message", login_name + ":" + text); });---「 name 」のタグが付いたときは、クライアントの名前 login_name を変更します。function の 中 の 変 数 な の で す が 、 connect 毎 に こ の 関 数 は 作 ら れ て 、 中 のlogin_name は個別に保持されます。つまりクロージャとして使われています。☆ 自分が発言したものも表示されて色分けてわかるようにしたり、切断時に誰が切断したか表示してみましょう。
  • 29. enchant.js の使い方次は enchant.js の RPG デモを改造して簡単に使い方を覚えます。● ローカルで開いてデモを動かす● 名前やフキダシの表示● 他のキャラクタの表示● 他のキャラクタをクリックを起点に移動
  • 30. まずデモを動かしてみるenchant.js のアーカイブを enchantjs とかに展開してローカルのファイルのenchantjs/examples/rpg/index.htmlを開いてみます。キーパッドを押すと動き回れることを確認して下さい。ゲームメイン部分ソースはenchantjs/examples/rpg/game.jsで、データ部分が大きいですが、それを除けば 80 行ほどとコンパクトです。このデモのソース自体の解説についてはこちらが詳しいのでおすすめenchant.js のサンプルコードを解読する( RPG 編その 1 ) | IDEA*IDEAhttp://www.ideaxidea.com/archives/2011/04/enchant_rgb_undocumented.html
  • 31. 例によって Hello World から--- ex8.js var label = new Label( "Hello World!" ); label.color = "black"; label.x = 7 * 16 - 8; label.y = 10 * 16;--- stage.addChild(label);---まず文字列のオブジェクトを作って色や表示位置を指定します。作ったオブジェクトを表示用のレイヤーに追加します。
  • 32. 名前とフキダシの表示addChild した順番に重ね合わせされるため、レイヤーを分ける必要があるので、 chara_group と message_group 作ります。CSS で見栄えを修正するためラベルに class の属性を追加してやります。index.html に CSS 追記し角丸半透明でフキダシが表示されるようにします。--- ex9.html.message{ text-align:center; border-radius:10px; -webkit-border-radius:10px; -moz-border-radius:10px; filter: alpha(opacity=75); -moz-opacity:0.75; opacity:0.75;}.login_name{ text-align:center;}
  • 33. 名前とフキダシの表示 (2)--- ex9.js var chara_group = new Group(); var message_group = new Group();--- // 名前の表示 player.login_name = new Label( " えぬせぐ " ); player.login_name._element.setAttribute( class, login_name );…略 // チャット内容の表示 player.message = new Label( "Hello World!" ); player.message._element.setAttribute( class, message );…略 // キャラクタ表示レイヤーとメッセージ表示レイヤーに追加 chara_group.addChild(player); chara_group.addChild(player.login_name); message_group.addChild(player.message);--- stage.addChild(chara_group); stage.addChild(foregroundMap); stage.addChild(message_group);---
  • 34. 名前とフキダシの表示 (3)動かしてみると、名前とフキダシがそのまま残ってしまいます。なので一緒に動くように修正します。this.moveBy(this.vx, this.vy);のところで移動をしているので、その下で名前とフキダシの位置も移動してやります。--- ex10.js this.login_name.x = this.x - 35; this.login_name.y = this.y + 32; this.message.x = this.x - 30; this.message.y = this.y - 16;---
  • 35. 他キャラクタの表示他の人を表示するため、 player の表示部分をそのまま使い、オブジェクトを作ってレイヤーに追加してやります。イメージを変更するために、 image2.draw の引数を変更して、表示に使うキャラクタを変えています。--- ex11.js var other_player = new Sprite(32, 32); other_player.x = 7 * 16 - 8; other_player.y = 11 * 16; var image2 = new Surface(96, 128); image2.draw(game.assets[chara0.gif], 100, 0, 96, 128, 0, 0, 96, 128); other_player.image = image2; // 名前の表示 other_player.login_name = new Label( " はくば " );…略 // キャラクタ表示レイヤーとメッセージ表示レイヤーに追加 chara_group.addChild(other_player); chara_group.addChild(other_player.login_name); message_group.addChild(other_player.message);---
  • 36. 他キャラクタの移動 (クリックでどっかへ移動)これだけではなにも動きが無くて動かそうとした時ちゃんと動くか不安です。このキャラクタがクリックされたら移動するようにしてみます。EventListener に touchend (クリックが離されたら)で動作を追加します。--- ex12.js // キャラクタが押されたら右へ移動していく other_player.addEventListener( touchend, function() { this.x += 4; this.login_name.x = this.x - 35; this.message.x = this.x - 30; });---キャラをクリックするたびに右へ移動していきます。
  • 37. メッセージの入力と変更チャットさせるためには文字入力をさせなければいけません。enchant.js で文字入力させる場合、 prompt を使わないと無理だそうです。なので、フキダシをクリックされたら prompt を出すようにしてみます。ついでにフキダシの内容も変更してみましょう。--- ex13.js // メッセージの入力とフキダシ内容変更 player.message.addEventListener(touchend,function(e) { var message = prompt( input message:, hi! ); if ( message != ) { player.message.text = message; } });---フキダシを押されたら prompt を表示して、中身が空でなければフキダシの中身を変更します。
  • 38. 通信部分と enchant の合体これまで作った node のチャット部分と enchant.js の部分とを合体していきます。まず public に置いて素の enchant デモ動くこと確認します。enchant.js と plugin/ui.enchant.js と images にある 4 つの画像ファイルapad.png pad.png chara0.gif map1.gifを public にコピーします。今まで enchant.js で編集していた index.html と game.js を public のフォルダに入れます。index.html で enchant.js 等の読み込み先を変更します。--- ex14.html <script type="text/javascript" src="enchant.js"></script> <script type="text/javascript" src="ui.enchant.js"></script>---
  • 39. node の通信部分を enchant.js に組み込むhtml に socket.io を読み込むための行を追加します。クライアントの先頭でチャットを作った時の接続部分を組み込みます。--- ex15.html <script type="text/javascript" src="/socket.io/socket.io.js"></script>--- ex15c.jsname = prompt("Input name:");var port = 20005;var socket = io.connect("/", { port: port });socket.on("connect", function() { socket.emit("name", name);});--- // 名前の表示 player.login_name = new Label( name );---サーバのコンソールに名前が送られてきているのを確認して下さい。
  • 40. メッセージをサーバに送ることと 他キャラクタへのフキダシ表示テストフキダシで入力する処理のところに socket.emit も追加します。また、ソケットに message が来たら other_player のフキダシを修正するようにします。--- ex16c.js // メッセージの入力とフキダシ内容変更 player.message.addEventListener(touchend,function(e) { var message = prompt( input message:, hi! ); if ( message != ) { player.message.text = message; socket.emit("message", message); } });--- // サーバからメッセージが来たら他のキャラクタのフキダシに表示 socket.on("message", function(text) { other_player.message.text = text; });---サーバが送ってきたメッセージ「 Hello Client! 」が表示されて、こちらから送ったメッセージがコンソールに表示されてることを確認して下さい。
  • 41. name が来たら新たなキャラクターを表示このままだと、他のユーザキャラクタが 1 体しか表示されないため、名前が送られてきたら新たなユーザがログインしたと認識して、新たなキャラクターを表示するようにします。そこで、今まで他のユーザを表示していたところを、 name が来たら動くクロージャを作ってくくってやります。--- ex17c.js // 他のユーザのログイン socket.on("name", function(text) { var login_name = text;…略 // 名前の表示 other_player.login_name = new Label( login_name );…略 });---複数の接続を行うと、それ毎にキャラクターが新しくその名前で表示されているのがわかります。また、メッセージを書くと変更されることも確認して下さい。
  • 42. ユーザ毎の処理を行えるようにする今は誰からのメッセージかを考慮せずにそのまま表示するので、すべてのクライアントのフキダシがかわってしまいます。そこで、誰からのメッセージなのかをタグに一緒に埋め込んで送って判別出来るようにします。今まではタグを単に「 message 」としていましたが「 message: 【ログイン名】」とするようにします。--- ex18.js // こちらがメッセージを受けた時の処理 socket.on("message", function(text) { console.log("message:" + login_name + " " + text); socket.broadcast.emit("message:" + login_name, text); });--- ex18c.js // サーバからこのユーザのメッセージが来たらフキダシに表示 socket.on("message:" + login_name, function(text) { other_player.message.text = text; });---ユーザ毎に違うメッセージが表示されていることを確認して下さい。キャラをクリックして少しずらしてやると見やすいです。
  • 43. position を送って移動移動できるように修正し、名前や位置などを player にまとめます。--- ex19.js var player = { login_name : "", x : 0, y : 0, message : "…" };その他 login_name など関連を player.login_name に修正--- // こちらがメッセージを受けた時の処理 socket.on("message", function(text) { console.log("message:" + player.login_name + " " + text); player.message = text; socket.broadcast.emit("message:" + player.login_name, text); });--- // 移動処理 socket.on("position", function(pos) { // console.log("position:" + player.login_name + " " + text); player.x = pos.x; player.y = pos.y; socket.broadcast.emit("position:" + player.login_name, pos); });
  • 44. position を送って移動 (2)--- ex19c.js socket.emit("position", { x : this.x, y : this.y });--- // サーバからこのユーザの移動が来たら移動させる socket.on("position:" + login_name, function(pos) { other_player.x = pos.x; other_player.y = pos.y; other_player.message.x = other_player.x - 30; other_player.message.y = other_player.y - 16; other_player.login_name.x = other_player.x - 35; other_player.login_name.y = other_player.y + 32; });※ この部分はもう削除しとく// キャラクタが押されたら右へ移動していく---☆ 余裕のある人は、他キャラクターの向き変更もしてみましょう。  direction 送って frame を direction にあわせて変更します。
  • 45. ログアウト時の処理接続が切れてもキャラクタが残るので、ログアウト時に削除しましょう。--- ex20.js // 切断した時の処理 socket.on("disconnect", function() { console.log("disconnect:" + player.login_name); socket.broadcast.emit("disconnect:" + player.login_name); });--- ex20c.js // 切断が送られてきたら表示とオブジェクトの消去 socket.on("disconnect:" + login_name, function() { // レイヤーから削除 chara_group.removeChild(other_player); chara_group.removeChild(other_player.login_name); message_group.removeChild(other_player.message); delete other_player; });---removeChild を使ってレイヤーからの削除を行います。☆ ログイン時に名前以外に位置やメッセージ情報も送ってみよう。
  • 46. 新たにログインしたユーザに 現時点でログインしてるユーザ情報を送る後からログインしたユーザは、その前にログインしていたユーザを見ることが出来ません。そのため、ログインした時に、今入っているユーザの情報を全て送ってやる必要があります。自分はここでちょっとつまづいてしまったので、せっかくなので皆さん考えてみてください。ex21 がログイン時にユーザ情報を送るバージョンのサンプルです。サンプルで動かしてる完成バージョンが下記ファイルです。example/enchat.jsexample/public/index.htmlexample/public/game.js
  • 47. 早く出来た人・後の時間用ネタXSS 対策  node-validate でサーバ側 フキダシ壊れるからクライアント側でもタグ落とすlogin_name 重複の対応名前とフキダシの表示リファクタリング  Chara クラスに機能追加 Chara.prototype = new Sprite();ログイン時に名前だけじゃなく場所とフキダシも送る ちゃんとやるには deferred 使う( DB から読み出す場合とかも)ゲーム化(ゾンビ感染ゲーム、雪合戦、 NPC を捕まえる、など)
  • 48. Special Thanks● @shi3z_bot enchant.js でメッセージ入力するにはどうしたらよいか困って いた時に的確なアドバイスをいただきました。 enchant.js というすばらしいフレームワークを提供いただいて いること自体にも感謝です。● @hkoba ログイン時に全ユーザ情報を送る処理について、クロージャ自 体をハッシュに突っ込もうとして出来なくて困ってた時にアドバ イスいただき、助かりました。● @KojiSaito ハンズオンで早く終わった人用になにか追加の課題を用意し ておいたら、というアドバイスいただき、使わせていただきまし た。