用Unity同时开发【微信小游戏】【安卓】【IOS】游

家电修理 2023-07-16 19:17www.caominkang.com电器维修

【系列文章目录】
文章目录
  • 【系列文章目录】
  • 前言
  • 一、导入UnityWebSocket插件
  • 二、在TS中使用

前言

本篇来实现WebSocket通信


一、导入UnityWebSocket插件

要在Unity中使用WebSocket我查看了官方文档
我一直觉得Unity是一个把所有东西都为开发者准备好的引擎
这次我错了,它摆烂了,Unity并没有为我们提供WebScoket的内容

所以只好使用插件了,这里我使用的是UnityWebSocket
网上也有很多教程用的是BestHttp
我也心动过,它好贵,坐等打折好了

言归正传,我们先在UnityWebSocket的Release页面下载插件
然后将它导入到我们的项目中
这个插件提供的Demo来供我们参考

二、在TS中使用

这个插件的使用是在C#中的,我们需要封装一层来让它能被TS使用
这里我定义了一个WebSocketClient

public class WebSocketClient
{
 private string connectAddress;
 protected IWebSocket _socket;

 public Action JSOnOpen;
 public Action JSOnMessage;
 public Action JSOnClose;
 public Action JSOnError;

 public ushort State
 {
  get
  {
   if (_socket == null)
   {
    return 0;
   }
   else
   {
    return (ushort)(_socket.ReadyState + 1);
   }
  }
 }
 //连接
 public void Connect(string address)
 {
  connectAddress = address;
  if (_socket == null)
  {
   _socket = ne WebSocket(address);
   _socket.OnOpen += Socket_OnOpen;
   _socket.OnMessage += Socket_OnMessage;
   _socket.OnClose += Socket_OnClose;
   _socket.OnError += Socket_OnError;
   _socket.ConnectAsync();
  }
 }

 //发送string
 public void SendStr(string str)
 {
  try
  {
   _socket.SendAsync(str);
  }
  catch (Exception e)
  {
   Debug.LogError(e);
  }
 }

 //发送byte
 public void SendByte(string data)
 {
  try
  {
   var bytes = System.Text.Encoding.UTF8.GetBytes(data);
   _socket.SendAsync(bytes);
  }
  catch (Exception e)
  {
   Debug.LogError(e);
  }
 }

 //关闭
 public void Close()
 {
  _socket.CloseAsync();
 }

 private void Socket_OnOpen(object sender, OpenEventArgs e)
 {
  JSOnOpen?.Invoke(connectAddress);
 }

 private void Socket_OnMessage(object sender, MessageEventArgs e)
 {
  try
  {
   if (e.IsBinary)
   {
    JSOnMessage?.Invoke(e.Data);
    //Debug.Log("WebSocket:" + string.Format("Receive Bytes ({1}): {0}", e.Data, e.RaData.Length));
   }
   else if (e.IsText)
   {
    JSOnMessage?.Invoke(e.Data);
    //Debug.Log("WebSocket:" + string.Format("Receive: {0}", e.Data));
   }
  }
  catch (Exception err)
  {
   Debug.LogError(err);
  }
 }

 private void Socket_OnClose(object sender, CloseEventArgs e)
 {
  JSOnClose?.Invoke(e.StatusCode, e.Reason);
  //Debug.Log("WebSocket:" + string.Format("Closed: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
 }

 private void Socket_OnError(object sender, ErrorEventArgs e)
 {
  JSOnError?.Invoke(e.Message);
  //Debug.Log("WebSocket:" + string.Format("Error: {0}", e.Message));
 }
}

需要注意的是,我们需要声明使用的Action类型,才能正常使用

_jsEnv.UsingAction();
_jsEnv.UsingAction();

别忘了为它生成一下胶水代码

接下来我们来在TS中继续工作

import { UnityWebSocket, WebSocketClient } from "csharp";
import { TSLog } from "../../CustomLog/TSLog";
import { IBaseMessageData, SocketMessageType, WebSocketState } from "../NetDefine";

//C#中我增加了一个Null类型
export enum WebSocketState {
 Null = 0,
 Connecting = 1,
 Open = 2,
 Closing = 3,
 Closed = 4
}

export interface IWebSocket {
 
 Connect(address: string): void;
 
 Send(data: IBaseMessageData, droppable?: boolean): void;
 
 Close(): void;
 
 ListenMessage(state: SocketMessageType, fun: Function): void;
 
 RemoveListen(state: SocketMessageType, fun: Function): void;
}

export class JSWebSocket extends WebSocketClient implements IWebSocket {
 private _aitSendCash: Array = ne Array();
 private _messageHandler: Map> = ne Map>();

 constructor() {
  super();
  this.JSOnOpen = this.Socket_OnOpen.bind(this);
  this.JSOnMessage = this.Socket_OnMessage.bind(this);
  this.JSOnClose = this.Socket_OnClose.bind(this);
  this.JSOnError = this.Socket_OnError.bind(this);
 }

 RemoveListen(state: SocketMessageType, fun: Function): void {
  if (this._messageHandler.has(state)) {
   let array = this._messageHandler.get(state);
   let neArray = ne Array();
   array.forEach(v => {
    if (v != fun) {
     neArray.push(v);
    }
   });
   this._messageHandler.set(state, neArray);
   array.length = 0;
   array = null;
  }
 }

 ListenMessage(state: SocketMessageType, fun: Function): void {
  if (!this._messageHandler.has(state)) {
   this._messageHandler.set(state, ne Array());
  }
  this._messageHandler.get(state).push(fun);
 }

 public Send(data: IBaseMessageData, droppable: boolean = true): void {
  let jstr = JSON.stringify(data);
  TSLog.Log("stringify:" + jstr)
  //判断连接
  if (this.State != WebSocketState.Open) {
   //未连接且非可抛弃数据加入待发送池
   if (!droppable) {
    this._aitSendCash.push(jstr);
   }
  }
  else {
   //已连接直接发送
   this.SendByte(jstr);
  }
 }

 private Socket_OnOpen(address: string) {
  TSLog.Log("OnConnect---->" + address);
  if (this._aitSendCash.length > 0) {
   TSLog.Log("sendcash")
   this._aitSendCash.forEach(jstr => {
    this.SendByte(jstr);
   });
  }

  this._aitSendCash.length = 0;
 }

 private Socket_OnMessage(jstr: string) {
  TSLog.Log("OnMessage---->" + jstr);
  if (jstr == "echo.ebsocket.events sponsored by Lob.") return;
  let jsdata: IBaseMessageData = JSON.parse(jstr) as IBaseMessageData;

  //解析Json根据类型分发Action
  if (this._messageHandler.has(jsdata.type)) {
   let handlers = this._messageHandler.get(jsdata.type);
   for (let i = 0; i < handlers.length; i++) {
    if (handlers[i] != null) {
     try {
      handlers[i](jsdata);
     }
     catch (e) {
      TSLog.Error(e);
     }

    }
   }
  }
 }

 private Socket_OnClose(errCode: UnityWebSocket.CloseStatusCode, reason: string) {
  TSLog.Log("OnClose---->" + reason);
 }

 private Socket_OnError(message: string) {
  TSLog.Log("Connect---->" + message);
 }
}

这样我们在TS中就可以使用WebSocket了

这里我定义了一个全局的mainSocket

export const mainSocket:IWebSocket = ne JSWebSocket();

以及一些配置和数据接口

export let mainSocketAddress: string = "ss://echo.ebsocket.events";
export let httpAddress: string = "";

export interface IBaseMessageData {
 type: SocketMessageType;
}

export enum SocketMessageType {
 Null = 0,
 Test = 1
}

export enum WebSocketState {
 Null = 0,
 Connecting = 1,
 Open = 2,
 Closing = 3,
 Closed = 4
}

在游戏中我们会有很多个功能使用到Socket
我不想在Socket中去为每个功能写处理
而是在每个功能的Hanlder中去处理
这里我写了一个TestHanlder来测试

export interface Req_Test_MessageData extends IBaseMessageData {
 data: {
  str: number,
  str2: number
 }
}

export interface Resp_Test_MessageData extends IBaseMessageData {
 data: {
  str: number,
  str2: number
 }
}

export interface ITestHandler{
 Connect(): ITestHandler;
 ReqTest(n1: number, n2: number): ITestHandler;
 Close(time: number): ITestHandler;
}

export class TestHanler extends Singleton implements ITestHandler {
 constructor() {
  super();
  mainSocket.ListenMessage(SocketMessageType.Test, this.OnRespTest.bind(this))
 }

 public OnRespTest(resp: Resp_Test_MessageData): void {
  TSLog.Log(resp.data.str)
  TSLog.Log(resp.data.str2)
 }

 public ReqTest(n1: number, n2: number): ITestHandler {
  let req: Req_Test_MessageData = {
   type: SocketMessageType.Test,
   data: {
    str: n1,
    str2: n2
   }
  }

  mainSocket.Send(req, false);

  return this;
 }

 public Connect(): ITestHandler {
  mainSocket.Connect(mainSocketAddress);
  return this;
 }

 public Close(time: number = 5000): ITestHandler {
  setTimeout(() => {
   mainSocket.Close();
  }, time)
  return this;
 }
}

然后我们就可以调用了

ne TestHandler()
 .Connect()  //连接服务器
 .ReqTest(5, 1)  //请求数据
 .Close(5000);   //关闭连接

嗯,挺简洁的,测试了也没有什么问题

具体内容还需要与服务端联调,目前以及实现了功能


Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by