首頁  >  文章  >  web前端  >  html5實作一個簡單的多人飛機遊戲實例詳解

html5實作一個簡單的多人飛機遊戲實例詳解

零下一度
零下一度原創
2017-05-13 15:36:483254瀏覽

一年多前看過一個多人聊天室應用,是張丹老師寫的一個 socket.io 教學 (原連結點不開,貼一個轉帖的),覺得socket這個東西很神奇。後來研究生期間的一個專案也用到了.Net的socket,多個客戶端之間的通信, 覺得很有意思,也是那一次比較全面地認識和應用了事件委託等等一些概念。最近受群裡研究mapbox的熱情和@扯淡大叔, @老羽 @F3earth 所有成員的幫助和啟發, 突發奇想花了點時間基於mapbox gl js和socket.io做了一個 飛機大戰遊戲! ,雖然功能介面很簡陋。而且程式碼也比較原始,還沒好好重構。但是基本上有了個架子,簡單就記下來分析下。如果對原始碼有興趣或想參與開發與最佳化工作,請造訪git倉庫: Jqmap2

整體架構

簡單來說,整個遊戲的設計想法就是:

伺服器從啟動開始就監聽任何客戶端發來了websocket 連接請求,有了連接(connection事件)後,就把客戶端初次發來的用戶名稱、當前飛機的坐標、朝向作為一個client 加入客戶端數據池(目前簡單處理為clients陣列)中。那麼至此一個客戶端的資料就同步到了伺服器端。

以後這個客戶端的飛機座標、朝向等資訊也定時發送(socket.send)給伺服器端,以便於伺服器端同時廣播(broadcast)給所有其他客戶端。那麼其實服務端就說清楚了,也就是負責轉機訊息,目的還是讓所有客戶視野中的玩家飛機狀態保持一致。

既然websocket是雙向通信,客戶端也需要定時發送訊息給伺服器端,更重要的是處理伺服器端發出的各種訊息(message事件),分辨哪些是歡迎用戶上線的訊息,普通的玩家位置同步訊息,抑或是A 擊敗了B 這樣的訊息。

這過程中前端和伺服器保持websocket 連接,並且不斷在通訊。相較於傳統的輪詢和long poll,這樣更節省流量和效能。整體來說,遊戲的邏輯是基於各種訊息事件的,connection事件產生一個socket連接,socket連接會有message 事件等等。

後端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了)。但前端需要根據業務需求將伺服器傳來的訊息分別處理

前端socket和飛機模型

前端業務相對複雜, 除了應對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物件 作為 mapbox api中source 的data,那麼是否一接到伺服器端訊息就去重繪所有飛機位置。這邊透過setInterval 定時呼叫source 的 setData()方法,實作重繪。

飛機子彈的軌跡計算,涉及到使用者按下空白鍵的瞬間飛機的位置和朝向,根據設定的子彈飛行時間做一個動畫顯示

子彈和敵機的碰撞偵測,簡化處理:設定一個常數作為飛機體積,在子彈飛行過程中即時計算子彈和敵機距離。在地圖處於小比例尺下增加偵測半徑,地圖處於大比例尺下方對應減少偵測半徑。

目前可能子彈飛行過程中碰撞偵測的計算量偏大,會有卡頓問題,CPU佔用較高,整個應用消耗記憶體100~130Mb左右... 好多小問題不說了。 。確實廢了一些腦子。

挑一、兩點分析下,一個是子彈的飛行過程,一個是Robot敵機的隨機行為控制

// 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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn