ホームページ  >  記事  >  ウェブフロントエンド  >  html5で簡単なマルチプレイ飛行機ゲームを実装する例を詳しく解説

html5で簡単なマルチプレイ飛行機ゲームを実装する例を詳しく解説

零下一度
零下一度オリジナル
2017-05-13 15:36:483253ブラウズ

1 年以上前に、Zhang Dan 先生が書いた、socket.io のチュートリアルを見ました (元のリンクが開けないので、再投稿しました)。その後、大学院時代のプロジェクトでも .Net ソケットを使用し、複数のクライアント間の通信が非常に興味深く、Events や Delegation などの概念を理解して適用した時期でもありました。最近、グループ内でのマップボックスの研究に対する熱意と、@开 Uncle、@老宇、@F3earth のメンバー全員からの支援とインスピレーションに触発されて、突然時間をかけて、マップボックス gl js とソケットをベースにした飛行機戦争ゲームを作成しました。 .io!ただし、機能インターフェイスは非常にシンプルです。さらに、コードは比較的原始的であり、適切にリファクタリングされていません。しかし、基本的にフレームワークはあるので、それを書き留めて分析するだけです。ソース コードに興味がある場合、または開発と最適化の作業に参加したい場合は、git リポジトリにアクセスしてください: Jqmap2

全体的なアーキテクチャ

簡単に言えば、ゲーム全体の設計アイデアは次のとおりです:

サーバーはリッスンします接続 (接続イベント) が確立された後、クライアントによって初めて送信されたユーザー名、座標、および現在の航空機の方向がクライアント データ プールに追加されます (現在は単純に処理されています)。クライアント配列)として。次に、クライアントのデータがサーバーに同期されます。

将来的には、クライアントの航空機の座標、機首方位、その他の情報も定期的にサーバーに送信され (socket.send)、サーバーが他のすべてのクライアントに同時にブロードキャストできるようになります。実際、サーバーはメッセージを中継する責任があることを明らかにしています。その目的は、すべてのクライアント間でプレイヤーの航空機のステータスを一貫した状態に保つことです。

WebSocket は双方向通信であるため、クライアントはサーバーに定期的にメッセージを送信する必要があります。さらに重要なのは、サーバーから送信されるさまざまなメッセージ (メッセージ イベント) を処理して、どのメッセージがユーザーをオンラインに歓迎するかを区別することです。ニュース、または A が B に勝ったというニュース。

このプロセス中、フロントエンドとサーバーは WebSocket 接続を維持し、常に通信を続けます。従来のポーリングやロング ポーリングと比較して、トラフィックとパフォーマンスが節約されます。一般に、ゲームのロジックはさまざまなメッセージ イベントに基づいており、接続イベントによってソケット接続が生成され、ソケット接続にはメッセージ イベントなどが含まれます。

バックエンド websocket

あまりにもナンセンスなので、いくつかの重要なコードを実装する方法を簡単に見てみましょう。

// バックエンドキープロセスの実装

var app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server); // 引入socket.io 库
io.on('connection', function(socket) { // 开始监听客户端的websocket连接请求,connection事件产生 socket 对象
    socket.emit('open'); // 向该客户端发送open事件.
    // init client drone obj for each connection !!
    var client = {
        name: false,
        color: getColor(),
        direction: 0,
        coordinates: [0, 0]
    }
    // message from client.
    socket.on('message', function(msg) {
        if (!client.name && msg.name) { // 如果是第一次连接,把用户的名字存储起来,并且广播给所有客户端。
          var obj  = { }; // 构建发送给其他客户端的消息
          obj = msg;
          clients.push(client); // 加入后台维持的客户端数组
          socket.broadcast.emit('message', obj); // 广播欢迎语给其他客户端
        } else if ( client.name == msg.name ) { // 客户端发来的飞机状态消息
            // 广播给其他客户端
          socket.broadcast.emit('message', obj);
        }
    }
}

バックグラウンド処理プロセスは、基本的に、クライアントから送信されたメッセージを受け入れ、他のクライアントに転送するだけで済みます (ランダムについては説明しません)。敵機の位置など。もちろん、すべてのクライアントが一連の敵機情報を共有するように後で変更され、同じ BOSS と戦うことができます。)ただし、フロントエンドは、ビジネス ニーズに応じてサーバーからのメッセージを個別に処理する必要があります

フロントエンド ソケットと航空機モデル

フロントエンド ビジネスは、WebSocket メッセージの処理に加えて比較的複雑です。 、位置、速度、方向、血液量、武器と装備などを含む一連の航空機データ モデルを構築する必要があります (非常に複雑になる可能性があるため、ここでは簡単に扱います)。

var socket;
try {
    socket = io.connect("http://123.206.201.245:3002");
    socket.on('open', function(){  // 当服务端确认连接后,开始发送第一次数据。
        statusBar.innerText = "已经连上服务器..";
        var askName = prompt("来,取个名字", "");
    }
    socket.on("message", function(json) { // 其实收到的是js 对象,这一点很牛逼。因为双向通信过程中传递的是 Binary 形式的数据,不需要再次解析了。
      if (json.type === "welcome" && json.text.name) {
          // .. 显示其他用户登录消息
      } else if (json.type === "defeat") {
          // .. 在前端的敌机数据模型中移除空血槽的飞机
      } else if (drone && json.text.name != drone.name) {
          // .. 传来的其他客户端飞机消息
          featureCol.features.forEach(function(drone) {
          // featureCol 是所有敌机数据集合,根据用户名check是更新还是新增.
          }
      }
   }

その他の問題には次のようなものがあります:

航空機データには、サーバーへの随時の変更アップロードとレンダリングが含まれます。レンダリングでは geojson オブジェクトをマップボックス API のソース データとして使用するので、サーバー側のメッセージを受信したらすぐにすべての航空機の位置を再描画する必要がありますか?ここでは、ソースの setData() メソッドが setInterval を通じて定期的に呼び出され、再描画が実装されます。

航空機の弾丸の軌道計算には、ユーザーがスペースバーを押した瞬間の航空機の位置と方向が含まれます。

弾丸と敵航空機との衝突検出により、処理が簡素化されます。 : set a 定数を航空機の体積として使用し、弾丸の飛行中に弾丸と敵機との距離をリアルタイムで計算します。地図の縮尺が小さい場合は検出半径が大きくなり、地図の縮尺が大きい場合はそれに応じて検出半径が小さくなります。

現時点では、弾丸飛行中の衝突判定の計算量が多すぎて、スタック問題が発生し、CPU使用率が高く、アプリケーション全体で約100~130Mbのメモリを消費する可能性があります。 . 言及しないと多くの小さな問題があります。 。本当に頭を使いました。

分析するポイントを 1 つまたは 2 つ選択してください。1 つは弾丸の飛行プロセス、もう 1 つはロボット敵機のランダムな動作制御です

// setPostion is to update Mydrone position.
function setPosition() {
    // direction in Rad. Generally, 1 Rad stands for 100km
    var current_rotate = map.getBearing(); 
    if (!manual && Math.random() > 0.95) { // 这边有意思,在每秒50帧的情况下,不是每一帧都会随机微调飞机的方向。而是5%的概率。
        direction += (Math.random() - 0.5) /5;
    }    
    // 根据飞机朝向和速度更新位置。
    point.coordinates[0] += speed * Math.sin(direction) / 100;
    point.coordinates[1] += speed * Math.cos(direction) / 100;
    // 校正飞机的朝向显示。因为默认情况下mapbox是根据你的视角随时调整图标方向。但实际上飞机图标的朝向必须和飞机运行方向一致,而不是简单的和标注一样。
    current_rotate = (-current_rotate) + direction * (180 / Math.PI);
}

以下は弾丸の飛行の計算プロセスです。

// start: fire location, target: bullet destination, duration: total animation time
function renderBulvar(start, target, direction, duration) {
    // target is geojson POINT, add Temp point in layer.. 
    var interval = 20, ratio = interval/duration, real_point = start, range = 0.4, count = 0, hitted = false;
    if (target.coordinates) {
        var targetSource = map.getSource('drone-target');
        window.setInterval(function(){
            if (count > duration/interval) { // 到达终点,不计算了
            } else {
                // 子弹每一帧跑一定比例的路程,最终到达指定终点
                real_point.coordinates[0] += Math.sin(direction)*ratio*range;
                real_point.coordinates[1] += Math.cos(direction)*ratio*range;
                targetSource.setData(real_point);
                if (!hitted){
                    hitted = testCrash(real_point.coordinates); // 感觉这里的hitted 有问题.
                }
                count += 1;
            }
        }, interval);
    }

到这里其实基本介绍了这个游戏的制作过程,经历了一些不成熟的想法,总共花了近十个小时完成目前的开发。还没有严谨地考虑过代码结构和 函数复杂程序,特别是子弹飞行和碰撞等部分,碰撞到后就终结子弹飞行等等。各位如果感兴趣,愿意完成 To DO list中的事情或者有何建议,请访问git仓库: Jqmap2 。请各位大神多提修改意见!

喜欢的同学请关注、收藏相关专题,会不断更新文章。希望和大家分享!!

【相关推荐】

1. 特别推荐“php程序员工具箱”V0.1版本下载

2. 免费h5在线视频教程

3. php.cn原创html5视频教程

以上がhtml5で簡単なマルチプレイ飛行機ゲームを実装する例を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。