そのような例の1つがチャットであり、リアルタイムで一緒に描画できる高度な機能を備えたWebソケット上で動作します。 これは、参加者が順番に、または動物のさまざまな部分を同時に描いてから、断片をまとめて何が起こったのかを見る、よく知られている子供向けゲームを連想させます。
この記事では、このようなドローイングマシンがどのように機能し、どのような困難に直面したかを簡単に説明します。 私はすぐにこれが完成品ではなく、単なるプロトタイプであることを指摘します。
Webソケット
すべては、Webソケットの動作を確立する必要があるという事実から始まりました。 私たちの場合、私たちはベースとして既製のチャットクライアントをベースとして少し血を管理しました
html5labs.com ブラウザーでサポートされている場合はネイティブWebソケットを介して実装され、そうでない場合はSilverlightを介したフォールバックを使用した実装の両方があることに注意してください。
上記のリンクからダウンロードできる例には、Webソケットのサポートのサーバー実装とクライアント部分の両方が含まれています。 この記事のフレームワークでは、クライアントのみに限定します。 デモでは、特定のアドレスのWebソケットを介した対話をサポートし、受信したメッセージをすべてのクライアントに送信することをサーバーについて知るだけで済みます。
いくつかの重要な詳細:
- Internet Explorer IEでは、Webソケットはネイティブにサポートされています 。第10バージョン以降、 IE10 PP4を使用しました 。
- Firefox Firefoxでは、ベンダープレフィックスを介してWebソケットにアクセスできるため、 WebSocketオブジェクトの代わりにMozWebSocketを使用する必要があります。
- オペラ Operaでは、設定:opera:config-> websockets-> enableを使用して、Webソケットを手動でオンにする必要がありました。
すべてがどのように機能するかを理解するために、簡単なテキストチャットから始めましょう。
<form id="myform"> <input type="text" id="chat" placeholder="type and press enter to chat" /> </form> <ul id="log"></ul>
フォームを送信するには、メッセージをインターセプトしてWebソケット経由で送信するイベントを切断します。
$("#myform").submit(function (event) { event.preventDefault(); // if we're connected // conn -- opened websocket connection if (conn.readyState === 1) { conn.send(JSON.stringify({ sender:sender, // sender ID type:'chat', chat:$('#chat').val() })); log.html('<li class="you">' + $('#chat').val().replace(/[<>&]/g, function (m) { return entities[m]; }) + '</li>' + log[0].innerHTML); $('#chat').value = ''; } });
上記のコードでは、接続の使用準備ができていることを確認し、チャットログにメッセージを追加しながら、オブジェクトをjson文字列として送信します。 (恐ろしい正規表現関数は単に「&」、「<」、「>」をエスケープします。
次に、Webソケットへの接続がどこから来たのかを考えてみましょう。 Webソケットの操作を開始するには、対応するオブジェクトを作成する必要があります。
if (conn.readyState === undefined || conn.readyState > 1) { // ws -- WebSocket or MozWebSocket conn = new ws('ws://yousite.com:port/chat'); ... }
さらに(内部)開いているソケットからいくつかのイベントハンドラーをハングアップする必要があります-少なくともメッセージを開き、閉じて、受信します(そして、できればエラー)。
conn.onopen = function () { state.toggleClass('success'); state.text('Socket open'); }; conn.onmessage = function (event) { var message = JSON.parse(event.data); if (message.type == 'chat') { // filter own messages if (message.sender != sender) { log.html('<li class="them">' + message.chat.replace(/[<>&]/g, function (m) { return entities[m]; }) + '</li>' + log[0].innerHTML); } } else { $('#connected').text(message); } }; conn.onclose = function (event) { state.toggleClass('fail'); state.text('Socket closed'); };
新しいメッセージは一括して全員に送信されるため、この送信者(ランダムに生成されたID)はコードでチェックされるため、独自のメッセージを除外することをお勧めします。
この時点で、まだWebソケットに精通していない場合(再び、サーバー側を記事の範囲外にする場合)、テキスト対話の実装の容易さにすでに触発されているはずです。 最も興味深いのは、テキストチャットの上に共同描画を書くのも非常に簡単なことです。
描画
ネット上には多くの例があるため、キャンバスに描画する方法にとどまることはおそらく冗長です。 私は3つの興味深い点だけを説明します。
まず、Firefoxは、MouseEventでoffsetX / offsetYをサポートしていないため、カーソルが位置するブロックに対するマウスの座標を決定できないことが非常に予想外でした。 私の記事「 T&P。Canvas and Offset 」も参照してください。 これはそれほど大きな問題ではありませんが、もちろん、完全にクロスブラウザーにする必要がある場合、コードが複雑になります。
第二に、予期せぬことに、ChromeにはCanvasにレンダリングする際にShadowが含まれておらず、一般に、異なるブラウザーは異なるアンチエイリアスとわずかに異なるアルゴリズムを使用することが判明しました。
(クリック可能)
そして第三に、この例でゲームをシミュレートするには、メッセージを送信するときにそれぞれ2つのキャンバスが使用され、どのキャンバスと何を正確に描画する必要があるかを理解する必要がありました。
さて、実際には、Webソケットを介した描画の転送に。 テキストチャットでフォームが送信されたときにメッセージが送信された場合、描画時には描画プロセス中に直接送信するのが妥当と思われるため、キャンバスにハングアップしたonmousemoveイベントに必要なコードを追加します。
// canvas - "canvas" object // canvas.source - jquery object for canvas // canvas.context - canvas.source[0].getContext("2d") canvas.source.bind("mousemove", function(e) { if (canvas.isPainting) { var line = {x1:canvas.lastPoint.x, y1:canvas.lastPoint.y, x2: e.offsetX, y2: e.offsetY}; drawLine(canvas.part, line); if (conn.readyState === 1) { conn.send(JSON.stringify({ sender:sender, type:"canvas", part:canvas.part, line:line })); } canvas.lastPoint = {x: e.offsetX, y: e.offsetY}; } });
メッセージ送信コードに注意してください-構造上、テキストのコードと違いはありません。
メッセージ受信を更新するために残ります:
conn.onmessage = function (event) { var message = JSON.parse(event.data); if (message.type == 'chat') { ... } else if (message.type == 'canvas') { if (message.sender != sender) { drawLine(message.part, message.line); } } else { ... } };
ここでも、ログにテキストを追加する代わりに、独自のラインと同じメカニズムを使用してソケットからラインを描画するだけで、違いはすべて同じです(必要に応じて色を変更できます)。
// c1 and c2 - global vars function drawLine(part, line) { var ctx = (part == 1) ? c1.context : c2.context; ctx.beginPath(); ctx.moveTo(line.x1, line.y1); ctx.lineTo(line.x2, line.y2); ctx.closePath(); ctx.stroke(); };
他のプレイヤーが何を描いているかが見えないように、ボックスシャドウと描画時の後半部分を介してもう少し光沢を追加します。
完成したサンプルはYa.Diskaからダウンロードできます。