首页 > 代码库 > Unity 发送游戏画面到 Winform

Unity 发送游戏画面到 Winform

一、首先看一下Unity界面:

技术分享

设了2个摄像机,位置重叠,旋转相同,父子关系,在父摄像机上加上脚本A.cs,并将子摄像机复制给A脚本中的变量Cam;

Cam用于为RenderTexture提供画面,Port是Socket监听的端口;

 

二、A.cs脚本代码(夜太深,改天再补充注释,直接贴代码)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;

public class A : MonoBehaviour
{
    public Camera cam;
    public int port = 10002;

    RenderTexture cameraView = null;
    Socket socket = null;
    Thread thread = null;

    bool success = true;

    /// <summary>
    /// 客户端列表
    /// </summary>
    Dictionary<string, Client> clients = new Dictionary<string, Client>();

    Vector3 old_position;//旧位置
    Quaternion old_rotation;//旧旋转

    void Start()
    {
        cameraView = new RenderTexture(Screen.width, Screen.height, 24);
        cameraView.enableRandomWrite = true;

        cam.targetTexture = cameraView;
        old_position = transform.position;
        old_rotation = transform.rotation;

        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
        socket.Listen(100);
        thread = new Thread(new ThreadStart(Accept));
        thread.Start();
    }

    int isNewAdd = 0;

    void Accept()
    {
        while (thread.ThreadState == ThreadState.Running)
        {
            Socket _socket = socket.Accept();
            if (clients.ContainsKey(_socket.RemoteEndPoint.ToString()))
            {
                try
                {
                    clients[_socket.RemoteEndPoint.ToString()].socket.Shutdown(SocketShutdown.Both);
                }
                catch { }
                clients.Remove(_socket.RemoteEndPoint.ToString());
            }

            Client client = new Client
            {
                socket = _socket
            };

            clients.Add(_socket.RemoteEndPoint.ToString(), client);
            isNewAdd = 1;
            Debug.LogError("连接……");
        }
    }

    void Update()
    {
        if (success && clients.Count > 0)
        {
            success = false;
            SendTexture();
        }

        if (isNewAdd > 0)
        {
            isNewAdd = 0;
            SendTexture(1);
        }
    }

    void OnGUI()
    {
        GUI.DrawTexture(new Rect(10, 10, 240, 135), cameraView, ScaleMode.StretchToFill);
    }

    void OnApplicationQuit()
    {
        try
        {
            socket.Shutdown(SocketShutdown.Both);
        }
        catch { }

        try
        {
            thread.Abort();
        }
        catch { }
    }

    Texture2D screenShot = null;

    int gc_count = 0;

    void SendTexture(int isInit = 0)
    {
        if ((!old_position.Equals(transform.position) || !old_rotation.Equals(transform.rotation)) || isInit == 1)
        {
            if (null == screenShot)
                screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
            RenderTexture.active = cameraView;
            screenShot.ReadPixels(new Rect(0, 0, cameraView.width, cameraView.height), 0, 0);
            RenderTexture.active = null;
            byte[] bytes = screenShot.EncodeToJPG(100);

            foreach (var val in clients.Values)
            {
                try
                {
                    val.socket.Send(bytes);
                }
                catch
                {
                    if (!val.socket.Connected)
                        clients.Remove(val.socket.RemoteEndPoint.ToString());
                    break;
                }
            }
            gc_count++;
            if (gc_count > 5000)
            {
                gc_count = 0;
                GC.Collect(2);
            }
            Debug.Log("发送数据:" + (float)bytes.Length / 1024f + "KB");

            old_position = transform.position;
            old_rotation = transform.rotation;
        }
        success = true;
    }
}

class Client
{
    public Socket socket = null;
}

 

三、Winform端

技术分享

直接拖了个PictureBox放到窗口上,停靠父窗体;

四、Winform代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TransformViewClient
{
    public partial class Form1 : Form
    {
        bool isOver = false;

        Socket socket = null;
        Thread thread = null;
        byte[] buffer = null;
        bool receState = true;

        int readTimes = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = true;

            buffer = new byte[1024 * 1024 * 10];

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(IPAddress.Parse("127.0.0.1"), 10002);
            thread = new Thread(new ThreadStart(Receive));
            thread.Start();
        }

        void Receive()
        {
            while (thread.ThreadState == ThreadState.Running && socket.Connected)
            {
                int count = socket.Receive(buffer);
                if (receState && count > 0)
                {
                    receState = false;
                    BytesToImage(count, buffer);
                }
            }
        }

        MemoryStream ms = null;
        public void BytesToImage(int count,byte[] bytes)
        {
            try
            {
                ms = new MemoryStream(bytes, 0, count);
                pictureBox1.Image = Image.FromStream(ms);
                readTimes++;

                if (readTimes > 5000)
                {
                    readTimes = 0;
                    GC.Collect(2);
                }
            }
            catch
            {
                
            }
            receState = true;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                socket.Shutdown(SocketShutdown.Both);
            }
            catch { }

            try
            {
                thread.Abort();
            }
            catch { }
        }
    }
}

 

程序里或许有许多bug和缺陷,希望高手指点!

技术分享

 

Unity 发送游戏画面到 Winform