IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 用Unity同时开发【微信小游戏】【安卓】【IOS】游戏#6.2 WebSocket通信 -> 正文阅读

[移动开发]用Unity同时开发【微信小游戏】【安卓】【IOS】游戏#6.2 WebSocket通信

【系列文章目录】



前言

本篇来实现WebSocket通信


一、导入UnityWebSocket插件

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

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

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

二、在TS中使用

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

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

    public Action<string> JSOnOpen;
    public Action<string> JSOnMessage;
    public Action<CloseStatusCode, string> JSOnClose;
    public Action<string> 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 = new 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.RawData.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<string>();
_jsEnv.UsingAction<CloseStatusCode, string>();

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

接下来我们来在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 {
    /**
     * 连接WebSocket
     * @param address 连接地址
     */
    Connect(address: string): void;
    /**
     * 发送数据
     * @param data Json数据
     * @param droppable 是否可抛弃,true在未连接状态下会被抛弃,false会等待连接后发送数据
     */
    Send(data: IBaseMessageData, droppable?: boolean): void;
    /**
     * 关闭连接
     */
    Close(): void;
    /**
     * 监听消息
     * @param state 监听的类型
     * @param fun 回调函数
     */
    ListenMessage(state: SocketMessageType, fun: Function): void;
    /**
     * 移除监听
     * @param state 监听的类型
     * @param fun 回调函数
     */
    RemoveListen(state: SocketMessageType, fun: Function): void;
}

export class JSWebSocket extends WebSocketClient implements IWebSocket {
    private _waitSendCash: Array<string> = new Array<string>();
    private _messageHandler: Map<SocketMessageType, Array<Function>> = new Map<SocketMessageType, Array<Function>>();

    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 newArray = new Array<Function>();
            array.forEach(v => {
                if (v != fun) {
                    newArray.push(v);
                }
            });
            this._messageHandler.set(state, newArray);
            array.length = 0;
            array = null;
        }
    }

    ListenMessage(state: SocketMessageType, fun: Function): void {
        if (!this._messageHandler.has(state)) {
            this._messageHandler.set(state, new Array<Function>());
        }
        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._waitSendCash.push(jstr);
            }
        }
        else {
            //已连接直接发送
            this.SendByte(jstr);
        }
    }

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

        this._waitSendCash.length = 0;
    }

    private Socket_OnMessage(jstr: string) {
        TSLog.Log("OnMessage---->" + jstr);
        if (jstr == "echo.websocket.events sponsored by Lob.com") 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 = new JSWebSocket();

以及一些配置和数据接口

export let mainSocketAddress: string = "wss://echo.websocket.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<TestHanler> 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;
    }
}

然后我们就可以调用了

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

嗯,挺简洁的,测试了也没有什么问题
测试结果
具体内容还需要与服务端联调,目前以及实现了功能


  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 23:03:58  更:2022-07-04 23:05:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:52:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码