いつものように、記事の最後には、githubのデモゲームとソースコードへのリンクがあります。
内容:
- ブラウザによるWebソケットのサポート
- オンラインゲーム開発
- 謝辞
- デモとソースコード
ブラウザによるWebソケットのサポート
一部の人々は、Webソケットはまだすべてのブラウザーでサポートされていないため、使用するには早すぎると考えています。 したがって、これらを使用する場合は、代替のトランスポート(Adobe®Flash®Socket、AJAXロングポーリング、AJAXマルチパートストリーミング、Forever Iframe、JSONPポーリング)と組み合わせてのみ使用してください。
ウィキペディアは、どのブラウザがWebソケットをサポートしているかを教えてくれます。
Google Chrome(バージョン4.0.249.0以降);
Apple Safari(バージョン5.0.7533.16以降);
Mozilla Firefox(バージョン4以降);
Opera(バージョン10.70 9067以降);
Internet Explorer(バージョン10以降);
ご覧のとおり、最も脆弱なリンクはInternet Explorerであり、バージョンは10分の1未満です。 liveinternet統計によると、ロシアの場合、バージョン9、8、7 、および6のInternet Explorerのシェアは、それぞれ1.4、1.7、0.5 、および0.1%です。 合計3.7%が得られます。 他のブラウザの古いバージョンを使用しているユーザーをこの図に追加すると、最終的な評価はわずかに増加する可能性がありますが、4%を超えるとは思いません。
これに基づいて、代替トランスポートの動物園を維持する必要があるか、これらのユーザーを忘れて生活する必要があるかどうかは、全員が自分で決定する必要があります。
公平に言えば、私は海外でInternet Explorerのシェアが大きく、そこにあるWebソケットのサポートの状況が対応していると言いたいです。 w3schools Webサイトの統計によると、バージョン9、8、7 、および6のInternet Explorerは、 それぞれ2.3、3.1、0.4 、および0.1%のシェアを持ち、5.9%です。
オンラインゲーム開発
だから、ここで要点に移ります。 PHPでのWebソケットサーバーの動作を示すために、簡単なゲームを書きたいと思いました。 最初に、どれを決める必要がありました。 おそらく彼女の唯一の要件はこれでした:
すべてのプレイヤーが同じマップ上にあり、他のプレイヤーと対話できる必要があります
「トースター」でこのページに出くわすまで、私は長い間このトピックをグーグルで検索しました 。ここで、 phpdaemonの開発者であるTravisBickleは、Webソケットの操作を示すシンプルなゲームのアイデアを提案するようコミュニティに依頼します。 回答のいくつかは非常に興味深いという事実にもかかわらず、この質問はほぼ3年前のものです...
すべての提案の中で、私は「タンク」を選択しましたが、開発プロセスが遅れず、デモがまだ見えず、私の心に残っていないように、彼らが提供しているものの簡易バージョンを作成し、本格的なゲームではないことにしました。
前の記事からチャットコードを取得し、次を使用してクライアント部分を少し追加しました。
-
canvas
とcontext
:タンクの画像を描画するオブジェクトのdrawImage
メソッド、長方形の塗りつぶしを行うfillText
、およびラベルの塗りつぶし(すぐにそれらを操作したことはありません) - 上、下、左、右、およびスペースキー(およびw、s、a、d)を処理するための
addEventListener
サーバー側では、クライアントからメッセージハンドラーをわずかに拡張しました。
- 各タンクは、座標、名前、および「ライブ」の数で構成される配列です
- 「up」、「down」コマンドがクライアントから送信される場合など、座標に対応する値を再計算し、タンクのすべての配列をクライアントに送信します
- jsonを使用してクライアントとのデータ交換が行われます
3つのタンクを持つサーバーからの応答の例
[{"名前": "adsa"、 "x":25、 "y":38、 "dir": "right"、 "health":0}、{"name": "qwe"、 "x": 20、“ y”:18、“ dir”:“ right”、“ health”:0}、{“ name”:“ sgfd4”、“ x”:5、“ y”:7、“ dir”:“ right "、" Health ":0}]
だから、私は戦車がスクリーンの周りを移動していることに気付きました。
50〜500人の同時プレイヤーを数えていたため、すべての戦車が1つの画面に収まらないことが明らかになったため、戦車の範囲を通常のバトルシティフィールドのサイズに制限し、ミニマップも追加しました。 元の黒の背景では、戦車が動いているかどうか、または他のすべてが不明確であるという事実のため、テクスチャを使用する必要がありました。 テクスチャの最適なバージョンを提供できる場合は、コメントにそのリンクを残してください。
次のステップは射撃でした。 そのためには、クライアントからのメッセージを処理するだけでなく、発射された発射体の動きを計算するタイマーを操作する必要があります(それぞれ1秒に10回、または100,000マイクロ秒ごとに十分であると判断しました)。
stream_select(array &$read, array &$write, array &$except, int $tv_sec [, int $tv_usec = 0])
関数
stream_select(array &$read, array &$write, array &$except, int $tv_sec [, int $tv_usec = 0])
を使用したことを思い出してください。これは、処理に必要なソケットの配列を受け入れ、変更が行われたときに動作しますそれら、またはタイムアウトによって。 この関数のタイムアウト機能を使用してタイマーを実装することが決定されましたが、残念なことに、何が起こったかはドキュメントに書かれていました。
タイムアウトを指定してstream_select関数を使用することはお勧めできません。 それでも決定する場合は、少なくとも200,000マイクロ秒のタイムアウトを使用することをお勧めします。
100,000マイクロ秒のタイムアウトでは、プロセッサの負荷は100%でした。
この点で、私は戦車が撃たなかったとしても、彼らはまだ相互作用するべきだと決めました。 だから私は彼らの衝突を処理し始めました:)
2つの戦車のどちらが正面衝突のポイントをカウントするか、側面衝突の難しさは明らかではありませんでした。 このため、私はこれら2つのあいまいなタイプの接触を放棄し、残りのオプションを1つだけ残しました。1つの戦車が他の戦車を後ろから攻撃しました。
これでやめることができるようです-「相互作用」の目標は達成されましたが、私はもっと欲しかったです。
さらに時間を費やした後、libeventを使用してタイマーを実装しました(現在、私のライブラリはsream_selectおよびlibeventで動作します)。
$this->base = event_base_new(); $this->event = event_new(); event_set($this->event, $this->_server, EV_READ | EV_PERSIST, array($this, 'accept'), $this->base); event_base_set($this->event, $this->base); event_add($this->event); $timer = event_timer_new(); event_timer_set($timer, array($this, '_onTimer'), $timer); event_base_set($timer, $this->base); event_timer_add($timer, 100000); event_base_loop($this->base);
賢い人は、event_timerは本質的にタイムアウトを持つバッファーであると書いており、stream_selectに似たようなことができるかどうかを調べることにしました 。 これを行う方法を知っている場合は、コメントに書いてください。
今、私はこの問題を次のように回避することができました:
$pair = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);// $pid = pcntl_fork();// if ($pid == -1) { die("error: pcntl_fork\r\n"); } elseif ($pid) { // fclose($pair[0]); $pair[1];// , sream_select } else { // fclose($pair[1]); $parent = $pair[0];// , 10 while (true) { fwrite($parent, '1'); usleep(100000); } }
その結果、プロセッサの負荷は約0%です。
今、私は射撃の可能性を追加することを妨げるものは何もありませんでしたが、私の友人の要請で、私は「衝突」の可能性を残すことにしました。
謝辞
最初の2つの出版物で、私のコードの欠点に注意を引いたすべての人々に感謝します。
Skpd 、 pavlick 、 mayorovp 、 truezemez 、 Fesor 、 sovok_kpss 、 spein 、 seriyPS
どうもありがとうございました。もちろん、+ 1カルマ。
あなたのおかげで、あなたは結果のライブラリの安定性と私へのより深い理解を達成することができました。
デモとソースコード
技術的な詳細:
- 同時に、戦車は発射物を1つしか発射できないため、マップ全体を撃つのではなく、敵を攻撃しようとします
- シェルが飛んでいる間、他のタンクを後ろに突っ込むことができます
- あなたのタンクは黄色、対戦相手は緑です
- すべての戦車は1つの大きなマップ上にあり、右上隅にあるミニマップでナビゲートします
- マップはプレイヤーの数に応じて自動的に増加しますが、後方には減少しません
- 障害物、ワシ、森林、手g弾など 実装されていません
デモゲーム(stream_selectを使用)
デモゲーム(libeventを使用)
ライブラリとサンプルのソースコードはgithubにあり、MITライセンスの下で利用できます。