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那 ...
随机推荐
- CAN总线中节点ID相同会怎样?
CAN-bus网络中原则上不允许两个节点具有相同的ID段,但如果两个节点ID段相同会怎样呢? 实验前,我们首先要对CAN报文的结构组成.仲裁原理有清晰的认识. 一.CAN报文结构 目前使用最广泛的CA ...
- A1020. Tree Traversals
Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...
- 【POJ1151】Atlantis
题目大意:给定 N 个矩形,求这些矩形的面积并. 题解:采用扫描线算法. 首先,按照矩形的横坐标排序,在纵坐标方向上维护一根扫描线被覆盖的长度,在这里采用线段树维护.统计答案时,从左到右扫描 2N 个 ...
- mysql数据库user表host字段的%问题
搜索: mysql数据库user表host字段的%问题 连接:http://blog.csdn.net/xiaomengh/article/details/48706149 在mysql数据库中,使用 ...
- STM32 一直进入串口接收中断
解决方法一: .串口初始化配置时,需要打开ORE 溢出中断,否则串口中断没有及时读取数据会触发溢出中断(打开接收中断默认开启溢出中断,但是为了读取溢出标志位还需要明确执行以下打开溢出中断),如果没有清 ...
- pandas简短介绍
1.数据结构 维数 名称 描述 1 Series 一维带标签单一数据类型的数组 2 DataFrame 不同数据类型的列 2.十分钟学习pandas 2.1.导入所需模块 import pandas ...
- java程序中加入@SuppressWarnings("serial")是什么意思?
比如有个类实现了java.io.Serialize接口:package com.onede4.test; public class TestSerial implements java.io.Seri ...
- 金融量化分析【day113】:PGEC策略
一.PGE简介 二.PGE代码 # 导入函数库 import jqdata import pandas as pd def initialize(context): set_benchmark('00 ...
- iframe伪造ajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 获取当前操作系统的ip
代码如下: #include "stdafx.h" #include <WinSock2.h> int get_local_ip() { WSADATA wsaData ...