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 = ; 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, );
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();
thread = new Thread(new ThreadStart(Accept));
thread.Start();
} int isNewAdd = ; 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 = ;
Debug.LogError("连接……");
}
} void Update()
{
if (success && clients.Count > )
{
success = false;
SendTexture();
} if (isNewAdd > )
{
isNewAdd = ;
SendTexture();
}
} void OnGUI()
{
GUI.DrawTexture(new Rect(, , , ), cameraView, ScaleMode.StretchToFill);
} void OnApplicationQuit()
{
try
{
socket.Shutdown(SocketShutdown.Both);
}
catch { } try
{
thread.Abort();
}
catch { }
} Texture2D screenShot = null; int gc_count = ; void SendTexture(int isInit = )
{
if ((!old_position.Equals(transform.position) || !old_rotation.Equals(transform.rotation)) || isInit == )
{
if (null == screenShot)
screenShot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
RenderTexture.active = cameraView;
screenShot.ReadPixels(new Rect(, , cameraView.width, cameraView.height), , );
RenderTexture.active = null;
byte[] bytes = screenShot.EncodeToJPG(); 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 > )
{
gc_count = ;
GC.Collect();
}
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 = ; public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = true; buffer = new byte[ * * ]; socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPAddress.Parse("127.0.0.1"), );
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 > )
{
receState = false;
BytesToImage(count, buffer);
}
}
} MemoryStream ms = null;
public void BytesToImage(int count,byte[] bytes)
{
try
{
ms = new MemoryStream(bytes, , count);
pictureBox1.Image = Image.FromStream(ms);
readTimes++; if (readTimes > )
{
readTimes = ;
GC.Collect();
}
}
catch
{ }
receState = true;
} private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
socket.Shutdown(SocketShutdown.Both);
}
catch { } try
{
thread.Abort();
}
catch { }
}
}
}
程序里或许有许多bug和缺陷,希望高手指点!

Unity 发送游戏画面到 Winform的更多相关文章
- 关于Unity的游戏的运行模式
游戏有个入口main函数,执行完main函数就返回 main函数中的步骤 1.初始化 2.while(true){ a.检查有没有消息,包括鼠标有没有被点击,键盘有没有被点击,自定义事件等等,有消息就 ...
- 《Unity 3D游戏客户端基础框架》概述
框架概述: 做了那么久的业务开发,也做了一年多的核心战斗开发,最近想着自己倒腾一套游戏框架,当然暂不涉及核心玩法类型和战斗框架,核心战斗的设计要根据具体的游戏类型而定制,这里只是一些通用的基础系统的框 ...
- [生活日记]参与unity非游戏行业开发者大会小结
今天下午花了半天时间公司全体都去人民广场参与了一个unity非游戏行业开发者大会,主要了解到unity这款全球顶尖之一的游戏引擎的一个发展史,从05年三个美国人技术研发开始,一直到12年开始引进中国, ...
- 自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药
自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析
自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 自制Unity小游戏TankHero-2D(3)开始玩起来
自制Unity小游戏TankHero-2D(3)开始玩起来 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的.仅 ...
- 自制Unity小游戏TankHero-2D(2)制作敌方坦克
自制Unity小游戏TankHero-2D(2)制作敌方坦克 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的. ...
- 自制Unity小游戏TankHero-2D(1)制作主角坦克
自制Unity小游戏TankHero-2D(1)制作主角坦克 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的. ...
- iOS端给unity发送消息,实现两者交互。
上一篇我们简单说了一下unity发消息给iOS端.现在我们就来说一下iOS端给unity发送消息的简单使用. 首先iOS端做得事情其实很简单就一句话,直接上代码 /** * 第一个参数:是unity那 ...
随机推荐
- shell(3)-mysql主从监控shell
需要先明白数据库主从同步正常的标准是来查看两个线程Slave_IO和Slave_SQL两个线程的工作状态: #!/bin/bash #Check MySQL Slave's Runnning Stat ...
- protobuf for java
本文档为java编程人员使用protocol buffer提供了一个基本的介绍,通过一个简单的例程进行介绍.通过本文,你可以了解到如下信息: 1.在一个.proto文件中定义一个信息格式. 2.使用p ...
- qsort代码(pascal/c/c++)与思想及扩展(随机化,TopK)
1.快速排序思想:从一堆数A中找到一个数x,然后把这堆数x分成两堆B,C,B堆的数小于(或小于等于)该数,放在左边,C堆的数大于(或大于等于)该数,放在右边,有可能把该数x单独分开,放在中间.然后对小 ...
- 编译RocketMQ
目前最新版本为 官方没有提供可执行的安装包,只提供了maven项目,去GitHub下载 点击Download ZIP 就可以了,如果你安装了版本控制工具 SVN 或者 GIT 就可以使用它上边的 UR ...
- operator的itemgetter和attrgetter
前几天在给个list做排序的时候,隐隐约约想起来有个语法糖可以替代lambda函数,用来获取list中dict的key,作为排序的key. 这个语法糖平时用得少,怎么都想不起来.今天查看python标 ...
- 使用sklearn进行数据挖掘
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...
- Scala进阶之路-Scala高级语法之隐式(implicit)详解
Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...
- 网络地址转换-NAT
网络地址转换-NAT 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NAT组网和常用术语 私网:局域网内IP 公网:因特网的公网ip地址 NAT设备:就是讲私网地址转换为公网的 ...
- OS + CentOS 7 / centos 7 / config / configuration / rescue / rc.local / yum
s centos7开启网卡功能 https://blog.csdn.net/nkd50000/article/details/78903479 网卡默认是关闭的,未分配ip地址,解决办法: 1.修改文 ...
- Xenserver 如何设置VM boot options
#1. SSH到xen物理机 #2. 查看VM的 uuid xe vm-list #3. 设置VM的BIOS xe vm-param-set uuid={vm uuid} HVM-boot-polic ...