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和缺陷,希望高手指点!

时间: 2024-08-06 21:42:39

Unity 发送游戏画面到 Winform的相关文章

自制Unity小游戏TankHero-2D(3)开始玩起来

自制Unity小游戏TankHero-2D(3)开始玩起来 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的.仅为学习Unity之用.图片大部分是自己画的,少数是从网上搜来的.您可以到我的github页面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源码. 本篇主要记录金币.按钮.坦克工厂.小地图等小部件,让整个场景初步成为一个可玩的游戏. 在本篇在制作过程中,

游戏开发(三)——WIN32 黑白棋(三)——游戏画面的现实

整个游戏分3部分介绍. 1.棋局的现实 2.AI的现实 3.游戏画面的现实 提供一下完整项目下载 这是第三部分:画面的显示 这部分其实就比较简单的,说白了就是api的堆砌. 主要了解下windows的消息机制,以及怎么画图 主要是分别封装了下对棋盘,棋子,以及当前轮到谁,当前比分是多少,就是游戏画面上不同的部分的绘制. void DrawReversiBoard(); void DrawReversiPieces(EnumReversiPiecesType type, int row_y, in

Unity 提取游戏资源之ktx转换

从雨松的博文<Unity3D研究院之mac上从.ipa中提取unity3D游戏资源(六十六)>可以学到提取Unity的游戏资源,其中有用到一个工具:PVRTexTool 因为这个工具的官网不好下载,故将其上传到CSDN,下载地址:http://download.csdn.net/detail/akof1314/7660209 提取出来的资源,其中的ktx资源,用PVRTexToolGUI.exe可以打开查看,可以发现都是上下颠倒,且被拉伸 直接转为png格式的批处理脚本为: 1 2 3 4 5

Unity网页游戏特点分析

Unity网页游戏是跑在浏览器的UnityWebPlayer插件中的,运行的模式是webplayer.unity3d+html 在嵌入UnityWebPlayer的网页中会调用UnityObject2的initPlugin函数,将webplayer.unity3d作为参数传入来初始化Unity网页游戏的运行环境 注:游戏dll及其他托管dll在构建Web版本时都会写入到webplayer.unity3d文件中 UnityObject2.js (其他链接1  其他链接2) 拥有检测 Unity W

自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药

自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的.仅为学习Unity之用.图片大部分是自己画的,少数是从网上搜来的.您可以到我的github页面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源码. 本篇主要记录声音.场景切换.武器弹药等. 关于碰撞 先插一句.上一篇记录了Unity3

【Unity NGUI游戏开发之五】多分辨率下完美分布式协同开发

NGUI多分辨率下完美分布式协同开发:不同分辨率下相对于屏幕坐标的Perfab数据不再丢失 NGUI多分辨率下完美分布式协同开发不同分辨率下相对于屏幕坐标的Perfab数据不再丢失 开发问题 原因分析 案例 完美过程 案例分析 实现过程 开发问题: NGUI分布式开发中,用git管理资源,团队成员每人负责一个perfab,所有现对于屏幕大小的相对位置的perfab因为引用了perfab外的数据,导致perfab的Anchor锚点数据丢失,最后的perfab集成后,必须重新设置,导致开发成本大幅度

?Unity 2D游戏开发教程之2D游戏的运行效果

Unity 2D游戏开发教程之2D游戏的运行效果 2D游戏的运行效果 本章前前后后使用了很多节的篇幅,到底实现了怎样的一个游戏运行效果呢?或者说,游戏中的精灵会不会如我们所想的那样运行呢?关于这些疑问,会在本节集中揭晓. (1)单击Unity上方,工具栏里的播放按钮,开始运行当前的游戏,默认精灵当前进入的是Idle动画状态,如图1-34所示. 图1-34  Idle状态 (2)当读者按下键盘上的左.右方向键,或者A.D键的时候,精灵会进入Walking动画状态,并且会向左或者向右移动,如图1-3

Unity制作游戏中的场景

Unity制作游戏中的场景 1.2.3  场景 在Unity中,场景(Scene)就是游戏开发者制作游戏时,所使用的游戏场景.它是一个三维空间,对应的三维坐标轴分别是X轴.Y轴和Z轴本文选自Unity 2D游戏开发从入门到精通清华大学出版社. 要创建一个新的场景,只需单击File|New Scene命令,或者按下快键键Ctrl+N,如图1-16所示. 图1-16  创建程序的命令,以及场景 默认情况下,新创建游戏项目的同时,也新创建了游戏的场景,只不过还没有保存罢了.使用快捷键Ctrl+S即可保

Unity 2D游戏开发教程之为游戏场景添加多个地面

Unity 2D游戏开发教程之为游戏场景添加多个地面 为游戏场景添加多个地面 显然,只有一个地面的游戏场景太小了,根本不够精灵四处活动的.那么,本节就来介绍一种简单的方法,可以为游戏场景添加多个地面.具体的操作方法是: (1)在Project视图里,新建一个文件夹,命名为Prefabs.然后将Hierarchy视图里的Platform对象,拖动到Prefabs文件夹中,如此一来就可以生成一个同名的预置资源,如图2-11所示. 图2-11  通过拖动对象到Project视图的方式,新建预置资源 (