在这里插入图片描述

一、静息状态

这个状态下,unity向服务器发送100,服务器返回已创建房间的端口,如下:

    void FixedUpdate()
    {
        requestCount+=Time.fixedDeltaTime;
        // 每秒发送一次请求
        if(requestCount>1f)
        {
            ws.Send(BitConverter.GetBytes(100));
            requestCount=0;
            for(int i=0;i<6;i++)
            {
                RoomList[i]=0;
            }
        }
    }
if playerNum==100:
	concatenated_data=b''
	for hostName in room_list:
		concatenated_data += struct.pack('i', hostName)
    await websocket.send(concatenated_data)
	continue

一、创建房间

创建房间时,Unity端读取下拉菜单的索引值,向服务器发送这个索引值

	public void AddRoom()
    {
        if ( ws.GetState() == WebSocketState.Open)
            ws.Send(BitConverter.GetBytes(dropDown.value+1));
        else
            Debug.Log(111);
    }

Python接收这个索引值,并返回端口(如果已经没有可用端口,就返回0)并创建新的进程

# 从端口中抽取未被占用的端口号
roomHost=None
for host in PublicHostList:
	if host in room_list:
		continue
    else:
        roomHost=host
        room_list.append(host)
    if roomHost is None:
        print('端口已满')
        # 发0
        await websocket.send(struct.pack('i', 0))
        continue
    else:
        # 发送在线的房间号
        concatenated_data=b''
        for hostName in room_list:
			concatenated_data += struct.pack('i', hostName)
        await websocket.send(concatenated_data)
        new_room=subprocess.Popen(['python3', 'roomServer.py'] + [str(playerNum),str(roomHost)])
        new_rooms.append(new_room)

三、进入房间

点击房间号切换场景,并保留端口号
在这里插入图片描述
在这里插入图片描述

四、完整代码如下:

服务端

import asyncio
import websockets
import struct
import subprocess

# 房间列表,房间内参数:人数;房间号(端口号)
room_list=[]

# 开放端口号
PublicHostList=[80]

# 活跃的房间
new_rooms=[]

# WebSocket服务器处理客户端连接的异步函数
async def echo(websocket):
    try:
        # 异步接收客户端发送的数据
        async for data in websocket:
            # 检查进程
            for index,new_room in enumerate(new_rooms):
                if new_room.poll() is not None:
                    print("房间"+str(room_list[index])+"已经结束")
                    new_rooms.remove(new_room)
                    room_list.remove(room_list[index])
            # 从数据中解包玩家人数
            playerNum = struct.unpack('i', data[:4])[0]
            
            if playerNum==100:
                concatenated_data=b''
                for hostName in room_list:
                    concatenated_data += struct.pack('i', hostName)
                await websocket.send(concatenated_data)
                continue
            print('请求的房间人数:'+str(playerNum))
            # 从端口中抽取未被占用的端口号
            roomHost=None
            for host in PublicHostList:
                if host in room_list:
                    continue
                else:
                    roomHost=host
                    room_list.append(host)
            if roomHost is None:
                print('端口已满')
                # 发0
                await websocket.send(struct.pack('i', 0))
                continue
            else:
                # 发送在线的房间号
                concatenated_data=b''
                for hostName in room_list:
                    concatenated_data += struct.pack('i', hostName)
                await websocket.send(concatenated_data)
                new_room=subprocess.Popen(['python3', 'roomServer.py'] + [str(playerNum),str(roomHost)])
                new_rooms.append(new_room)
        
            
    except websockets.exceptions.ConnectionClosed:
        print("连接已关闭")

# 启动WebSocket服务器的异步函数
async def main():
    # 启动WebSocket服务器
    async with websockets.serve(echo, "0.0.0.0", 3389):
        # 保持服务器运行
        await asyncio.Future()

# 运行WebSocket服务器
asyncio.run(main())

客户端

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using HybridWebSocket;
using System;
using UnityEngine.UI; 
using System.Linq;
public class updateRoom : MonoBehaviour
{
    // Start is called before the first frame update
    private WebSocket ws; // WebSocket 实例
    public string IP;
    public GameObject[] RoomButtonList;
    public int[] RoomList;
    public Dropdown dropDown;
    public float requestCount;
    void Start()
    {
        // 创建 WebSocket 实例
        ws = WebSocketFactory.CreateInstance(IP);

        // 添加 OnOpen 事件监听器
        ws.OnOpen += () =>
        {
            Debug.Log("WS connected!");
            Debug.Log("WS state: " + ws.GetState().ToString());
        };

        // 添加 OnMessage 事件监听器
        ws.OnMessage += (byte[] msg) =>
        {
            RevAction(msg);
        };

        // 添加 OnError 事件监听器
        ws.OnError += (string errMsg) =>
        {
            Debug.Log("WS error: " + errMsg);
        };

        // 添加 OnClose 事件监听器
        ws.OnClose += (WebSocketCloseCode code) =>
        {
            Debug.Log("WS closed with code: " + code.ToString());
        };
        ws.Connect();

    }

    void OnDestroy()
    {
        if (ws != null)
        {
            ws.Close();
        }
    }
    
    void RevAction(byte[] msg)
    {
        
        for(int i=0;i<msg.Length/4;i++)
        {
            int roomHost=BitConverter.ToInt32(msg, i*4);
            Debug.Log(roomHost);
            RoomList[i]=roomHost;
            
        }
    }

    void FixedUpdate()
    {
        requestCount+=Time.fixedDeltaTime;
        // 每秒发送一次请求
        if(requestCount>1f)
        {
            ws.Send(BitConverter.GetBytes(100));
            requestCount=0;
            for(int i=0;i<6;i++)
            {
                RoomList[i]=0;
            }
        }
        
        // 给发送
        for(int i=0;i<6;i++)
        {
            RoomButtonList[i].GetComponent<enterRoom>().myHost=RoomList[i];

            Transform child = RoomButtonList[i].transform.GetChild(0);

            // 检查子对象是否有Text组件
            Text childText = child.gameObject.GetComponent<Text>();
            if (childText != null)
            {
                // 修改Text组件的文本
                if(RoomList[i]!=0)
                    childText.text = "房间号:"+RoomList[i];
                else
                    childText.text = "";
            }
            
        }
    }

    // 添加房间
    public void AddRoom()
    {
        if ( ws.GetState() == WebSocketState.Open)
            ws.Send(BitConverter.GetBytes(dropDown.value+1));
        else
            Debug.Log(111);
    }
}

客户端场景切换

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class enterRoom : MonoBehaviour
{
    public int myHost;
    public SaveParam SaveParam;
    
    // Start is called before the first frame update
    void Start()
    {
        GetComponent<Button>().onClick.AddListener(EnterRoom);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    

    // 加入房间
    public void EnterRoom()
    {
        if(myHost==0)
            return;
        // 跳转场景
        SceneManager.LoadScene("双人房");
        // 保存端口
        SaveParam.Host=myHost;
    }

    // 退出房间
    public void OutRoom()
    {
        SceneManager.LoadScene("Start");
    }
}

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐