[尝试在事件函数中分配值时挂起

问题描述 投票:0回答:1

我正在创建必须与服务器通信的多人游戏。为了进行通信,我制作了一个ClientObject,它不断等待来自服务器的消息。接收到消息后,它将解密消息内容并与该消息一起发送事件。在广播事件时触发的函数中,我尝试将部分消息分配给PlayerObject。例如,其他玩家的名字。我的问题是,当到达Players [i] .Name = name [i]时,程序挂起。调试显示name [i]是期望值。 Player [i] .Name在分配时为null,但它是可用的String变量,因此该行应该有效。

客户端对象:

public class ClientObject
{
    public Socket clientSocket;
    public void Connect()
    {
        IPEndPoint serverAddress = new IPEndPoint(IPAddress.Parse("192.168.56.1"), 3000);

        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(serverAddress);
        Thread thread = new Thread(new ThreadStart(ReceiveMessage));
        thread.Start();
    }

    public void ReceiveMessage() {
        try
        {
            while (true)
            {

                byte[] rcvLenBytes = new byte[4];
                clientSocket.Receive(rcvLenBytes);
                int rcvLen = System.BitConverter.ToInt32(rcvLenBytes, 0);
                byte[] rcvBytes = new byte[rcvLen];
                clientSocket.Receive(rcvBytes);
                String rcv = System.Text.Encoding.ASCII.GetString(rcvBytes);



                MessageReceivedEventArgs args = new MessageReceivedEventArgs();
                args.Message = rcv;

                if (TestMessageRecevied != null)
                {
                    TestMessageRecevied(this, args);
                }
            }
        }
        catch
        {

        }
    }


    public delegate void MessageHandler(object sender, MessageReceivedEventArgs e);
    public event MessageHandler TestMessageRecevied;
}
    public class MessageReceivedEventArgs : EventArgs
{
    public string Message { get; set; }

}

播放器对象:

public class PlayerObject
{

    public string Name 
    {
        get;
        set;
    }

    public bool ReadyState
    {
        get;
        set;
    }

    public int DiceLeft
    {
        get;
        set;
    }

}

就绪菜单:

在这种情况下,我分配了一个PlayerObject.Name变量,但是如果我尝试更改图像精灵或UI中文本对象的值,它也会挂起。因此,分配似乎是一个问题,但无法锻炼。如果我在Start()方法中进行赋值,则可以正常工作。

public class ReadyMenu : MonoBehaviour
{

    ClientObject client;

    public GameObject backgroundPanel;
    public Sprite tick;
    public Sprite cross;

    Text pName;
    Image imgCheck;

    PlayerObject[] players;

    // Start is called before the first frame update
    void Start()
    {
        pName = GameObject.Find("PlayerPanel1/Name").GetComponent<Text>();

        players = new PlayerObject[6];
        client = new ClientObject();
        client.TestMessageRecevied += Client_MessagedReceived;
        client.Connect();
        SendClientMessage(PlayerPrefs.GetString("name"));

    }

    private void Client_MessagedReceived(object sender, MessageReceivedEventArgs e)
    {
        Debug.Log("In C_MR: " + e.Message);
        string message = e.Message;

        if (message.Contains("READY"))
        {
            //NOT IMPLEMENTED YET

            return;
        }
        if (message.Contains("PLAYERS"))
        {
            //Message before split
            Debug.Log(message);
            message = message.Substring(7);

            //Cut PLAYERS from the string
            Debug.Log("substring: "+message);

            //Seperate names
            char[] sep = { ' ' };
            String[] names = message.Split(sep,StringSplitOptions.RemoveEmptyEntries);

            Debug.Log("after name split");
            Debug.Log("names length is: "+names.Length);
            Debug.Log("names 0 is: "+names[0]);

            for (int i = 0; i < names.Length; i++) 
            {

                Debug.Log("in loop, i = "+i);

                Debug.Log("in loop, setting playerobject name");
                players[i] = new PlayerObject();
                players[i].Name = names[i];
                Debug.Log("in loop, after setting playerobject name");

                //GameObject panel = GameObject.Find("PlayerPanel" + (i + 1));
                //Debug.Log("in loop, activate apnel");
                //panel.SetActive(true);
            }
            Debug.Log("finsihed");
        }

    }

名称为test的输出

在C_MR中:PLAYERStest

PLAYERtest

子字符串:测试

分割后

名称长度为:1

名称0是:测试

循环中,i = 0

循环中,设置播放器对象名称

c# unity3d events client-server
1个回答
0
投票

您的问题源于您实际上并没有用players填充PlayerObject数组的事实。只做PlayerObject[] players = new PlayerObject[6]您只是在创建一个包含六个空对象的数组。

因此,当您尝试访问player.Name属性时,您正在尝试对空对象进行访问。这应该抛出一个NullReferenceException,但是您正在Client_MessagedReceived函数中的异步上下文中工作,并且异常似乎并不总是可悲地找到回到主线程的方式。

因此,您只需要用players填充PlayerObject数组,就可以了。您可以在设置名称(即players[i] = new PlayerObject())之前执行此操作,只要名称更改在应用程序生存期内仅发生一次,或者在创建players数组时执行即可。

© www.soinside.com 2019 - 2024. All rights reserved.