日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

【联机对战】微信小程序联机游戏开发流程详解

發布時間:2023/12/4 综合教程 49 生活家
生活随笔 收集整理的這篇文章主要介紹了 【联机对战】微信小程序联机游戏开发流程详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

現有一個微信小程序叫中國象棋項目,棋盤類的單機游戲看著有缺少了什么,現在給補上了,加個聯機對戰的功能,增加了可玩性,對新手來說,實現聯機游戲還是有難度的,那要怎么實現的呢,接下來給大家講一下。

考慮到搭建聯機游戲的服務器成本不小,第一個想法是用小程序的藍牙功能實現游戲聯機的,但是其API接口提供的藍牙硬件支持兼容問題不少,暫時不去折騰了,現在采用UDP通信就很容易實現,可以在WIFI局域網內讓兩個以上小程序實現通信。

UDP通信

先來了解一下 UDP通信 的工作原理,這是一個面向無連接的傳輸協議,是UDP通信,與之對應的是 面向可連接的傳輸協議,是 TCP通信

從上圖看出來,UDP通信的方式很簡單,可以想象它們能充當其中一個角色,

  • client客戶端: 只負責發送報文
  • server服務端:只負責接收報文

小程序實現UDP通信,要創建client客戶端和服務端server,各占一個socket端口,
對初學者來說,第一次接觸不好理解,端口,可比喻成線路一端的接口。

TCP通信的面向連接是比UDP通信最可靠的,那為什么不優先采用TCP通信呢

小程序的TCP通信實現過程中,需要綁定到wifi,這一點獲取wifi信息的處理有遇到問題,對新手來說是比較麻煩的,暫且避之,能正常獲取到wifi信息再來考慮

client客戶端

直接在一個模塊文件中實現,這個在項目中的文件是lan.js,可以理解它為局域網工具模塊,

負責發送

要向server服務端發送報文(消息),就寫一個方法sendMessage(e)來調用,傳入服務端的remoteInfo,實現代碼如下

import Util from './util';function sendMessage(e){//需要傳入的參數const { message, port, remoteInfo, fail, success, autoClose } = e;let udp = wx.createUDPSocket();udp.onError(err=>{//...這里處理初始化udp的錯誤});udp.onMessage(res=>{const { remoteInfo, localInfo } = res;if(autoClose) udp.close();//默認自動關閉udp//消息res.message是ArrayBuffer對象,要轉換為json object對象才好處理let message = Util.arrayBufferToString({data:res.message});message = Util.parseJSON(message);//返回服務端響應的數據success(message,remoteInfo,localInfo);});//綁定端口udp.bind(port);//發送消息message 到服務端 `address(IP)`和`port(端口)`udp.send({address:remoteInfo.address,port:remoteInfo.port,message:toStringMesssage(message)});return udp;
}

客戶端向服務端發出消息,沒必要加請求超時的處理,后面有個邏輯是處理連接的,用它代替連接超時處理的判斷

連接服務端

客戶端連接到服務端方法是connectServer(remoteInfo,e),實現代碼如下,加了定時連接請求,如果請求超時了,就會提示用戶連接超時(連接斷開)

const Timeout = 6000;//超時6sfunction connectServer(remoteInfo,e){const { config, onReceive, onError, onConnect, onDisconnect } = e;let connectInfo;let timer,timer2;//關閉定時器const closeTimer = function(){if(timer) {clearTimeout(timer);timer=undefined;}if(timer2) {clearTimeout(timer2);timer2=undefined;}};const clientUdp = wx.createUDPSocket();clientUdp.onClose(function(){closeTimer();});clientUdp.onError(function(err){closeTimer();//...這里處理udp拋出的錯誤,回調onErroronError(err);});//默認不傳port,就綁定一個隨機的port(端口號)clientUdp.bind();let time;let sendSign = function(){//定時發送timer = setTimeout(function(){let message = {intent:'keep_connect',ntime:Date.now(),};if(!connectInfo){message.intent='create_connect';message.data=config;}//定時向服務端發送連接信息clientUdp.send({address:remoteInfo.address,port:remoteInfo.port,message:JSON.stringify(message)});//加個定時器,用于超時判斷timer2 = setTimeout(function(){    connectInfo = null;onDisconnect({ errMsg:'the request timeout' });},Timeout);},config.time || 3000);};clientUdp.onMessage(function(res){//防抖處理closeTimer();const { localInfo,remoteInfo } = res;let message = Util.arrayBufferToString({data:res.message});message = Util.parseJSON(message);if(message.intent=='create_connect'){connectInfo = remoteInfo;//回調連接事件onConnect({message:message.data,localInfo,remoteInfo});}else{if(time && message.otime==undefined) message.otime = Date.now() - time;//回調接收事件onReceive({message,localInfo,remoteInfo});time = Date.now(); }sendSign();});//開始發送sendSign();return clientUdp;
}

方法sendSign()就是發送信號的意思,可以這樣認為,在網絡上冒個泡,可以讓對方知道你在線,主動找你溝通,如果超過時間還不吐泡泡,就認為你潛水了(隱身)

server服務端

負責接收

接下來,寫一個叫服務端server的創建方法createServer(),用于監聽客戶端發來的連接請求,還要處理其它的請求,稍微復雜一點,實現代碼如下

import Util from './util';function createServer(e){const { config, onReceive, onError, onConnect, onDisconnect } = e;let udp = wx.createUDPSocket();udp.onError(function(err){//...這里處理udp拋出錯誤,回調onErroronError(err);});udp.onClose(function(){closeTimer();});udp.onMessage(function(res){const { localInfo, remoteInfo } = res;let message = Util.arrayBufferToString({data:res.message});message = Util.parseJSON(message);let response;switch(message?.intent){case 'create_connect'://...處理創建連接請求break;case 'keep_connect'://...處理保持連接請求break;default://如果沒處理,就交給回調onReceive處理response = onReceive({ localInfo, remoteInfo, message });}//如果還沒處理,就不需要響應了(不理睬)if(!response) return;//服務端響應數據發給客戶端udp.send({address:remoteInfo.address,port:remoteInfo.port,message:toStringMesssage(response)});});//綁定一個服務器端口let port = udp.bind(config.port);return {getPort(){return port;},close(){udp.close();}};
}

有沒有覺得,服務端的處理邏輯很像web的服務器處理請求,處理響應來自客戶端(瀏覽器)的請求

管理客戶端連接

再具體一點,處理創建和保持連接請求的方法,將上面的代碼改一下,添加后的代碼如下

const Timeout = 6000;//超時6s
//...let connectInfo;let timer;//保持連接(定時連接檢查)const keepConnectInfo = function(){timer = setTimeout(function(){if(connectInfo){let otime = Date.now()-connectInfo.utime;//未超時if(otime<Timeout){keepConnectInfo();onReceive({ //...回調接收事件,返回連接狀態});return;}}connectInfo=null;//若連接超時了,就回調斷開連接的方法onDisconnect({ errMsg:'wait update is timeout'});},Timeout);};//關閉定時器const closeTimer = function(){//...};switch(message?.intent){case 'create_connect'://創建連接請求{let data = message.data;connectInfo = {//...記錄連接信息};//回調連接事件onConnect({//...傳連接數據});response = {intent:message.intent,//...返回連接后獲取的初始化數據};//防抖處理closeTimer();keepConnectInfo();break;}case 'keep_connect'://保持連接請求{if(connectInfo) {connectInfo.utime = Date.now();response = {intent:message.intent,//...};}else{response = {intent:'create_connect',//...返回配置數據data:config,};}//記錄時間差if(message.ntime) response.utime = response.time - message.ntime;break;}default://如果沒處理,就交給回調onReceive處理response = onReceive({ localInfo, remoteInfo, message });}//...

可以看出來,這里連接的邏輯是定時檢查客戶端連接更新的狀態,如果超過時間不更新,就判斷為連接超時

局域網廣播

兩個小程序之間是怎么知道對方的IP和端口呢,這就要借助廣播IP地址了,

發送廣播IP地址,就可以在局域網發現在線的設備,然后請求連接,廣播過程是這樣的

來打個比喻:

客戶端A(你)發送廣播消息(點餐訂單),交給路由器(平臺)處理,路由器會轉發消息,附帶了你的IP(家)地址和端口(門號),到其余的客戶端(搶單),
如果有客戶端(搶到單的外賣服務員)對方想回應你,就會給你發消息:你的外賣到了…(票據上有寫了對方的IP(店鋪)地址和端口(門牌號))

發送廣播

客戶端怎樣發送廣播呢,這個方法是sendBroadcast(),很容易實現,代碼如下

function sendBroadcast(e){const { port, fail, success, showLoading } = e;let udp = wx.createUDPSocket();let timer;let list = [];//記錄接收的列表function complete(callback){//...udp.close();//處理完要關閉callback();}if(fail instanceof Function){udp.onError(function(err){complete(function(){fail(err);});});}udp.onMessage(function(res){//將接收的消息轉換成json對象res.message = toDataJSON(res.message);list.push(res);});udp.bind();//發送廣播消息,其中port是指定小程序的服務端接收端口udp.send({address:'255.255.255.255',port: port,message: JSON.stringify({ intent: 'scan' })});//加上定時timer = setTimeout(function(){//到時結束complete(function(){if(success instanceof Function) success({ list });})}, e.timeout || 3000);//...
}

廣播IP是255.255.255.255,就是發給局域網內的路由器,需要注意的是,不是所有的路由器都是支持廣播IP的,要確保支持它,需要登錄路由器的控制頁面,找看有沒有其中的隔離AP項,取消勾選即可

發送的廣播消息是{ intent: 'scan' },需要從另一個小程序的服務端負責接收那方法onReceive()中處理這個廣播消息,返回響應數據

游戲聯機

實現游戲的聯機方式分兩種,上面開始講過,用其中的一個角色:服務端或者客戶端

主動加入

一種是主動加入游戲,就用客戶端發送問候消息方法sendMessage(e)去請求服務端,服務端會處理響應請求

加入前,客戶端需要先知道對方的IP地址和端口,從上面講得發送廣播方法sendBroadcast(e)來掃描一下,找到對方后,然后發送加入請求
在對方的服務端返回同意消息時,附帶了游戲入口消息,告訴客戶端加入游戲的途徑

主動等待

另一種,是主動創建好游戲地盤,創建好服務端,用一個接收數據的綁定的端口,去負責監聽客戶端發來的請求,然后處理響應數據

這里注意不要搞錯,當另一個小程序客戶端發來加入游戲的請求時,要留點心,別把客戶端的端口號當作服務端的端口號(接收數據)

關于項目

好了,UDP通信的方法就講到這里,這樣有了大致的方向,

如需要看項目源碼的請在 下載列表點這里 找聯機游戲相關的項目,那些聯機游戲項目里都有應用,有對應的介紹,請放心下載,多謝支持,愿學有所獲!

打開項目源碼,如果遇到微信開發工具提示Error: 登錄用戶不是該小程序的開發者 ,需要替換項目的測試號替換為自己的,點擊開發工具右邊的詳情,里面有AppID,可修改替換,

這里有一個中國象棋-單機游戲開發流程詳解文章,需要的同學可以先看看,

這里是在原單機游戲項目的基礎上增加了聯機功能,聯機游戲運行的動圖效果如下

聯機測試

項目還沒有自己的測試號,就前往申請一個測試號,申請成功后,登錄如下圖,其中AppID的就是

  • 申請測試號 🔗傳送門

開發工具上掃碼預覽出來的小程序是開發版,只能在自己的微信上體驗,想測試聯機游戲就這樣做,選擇里面的真機調試項,這樣就可以模擬兩個用戶來體驗了,一個在開發工具上模擬器上,另一個就是自己的真機微信上

如果有兩個手機微信就這樣試試,用兩個手機微信分別登錄開發工具弄一個開發版小程序來,這樣兩個手機微信上就能測試游戲聯機,

上面操作有點麻煩,就用自己申請好的一個小程序來測試,發布一個體驗版小程序就可以讓很多人參與測試了。

總結

以上是生活随笔為你收集整理的【联机对战】微信小程序联机游戏开发流程详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。