前言:Unity3D笔记是我平时做一些好玩的测试和研究,记录的笔记。会比较详细也可能随口一提就过了。 所以大家见谅了,内容一般都会是原创的(非原创我会注明转载)。由于很多内容其他的朋友也肯定研究发表过,大家用于指出错误。
前段时间,公司有一个针对游乐园的项目。项目是基于安卓3399板子的,会检测一些红外的触碰来替代鼠标当作输入。本来以为那么就 Launcher 里有个服务,检测到有触碰那么转换下屏幕坐标之后模拟鼠标点击就可以了。可是真是用的时候发现了一些局限性:
1.鼠标点击是单一事件,不可能同一时间点击多个地方。
2.延迟其实有点大,虽然就零点几秒。但是我们的项目对延迟比较看重。
所以提出了第二个方案:红外检测到数据后Launcher的服务通过坐标转换成屏幕坐标,通过UDP全网广播,游戏和桌面监听(桌面也需要通过触碰打开游戏等等)。所以就需要我专门做一个unity能用的UDP监听功能,并转换成输入。
一.UDP广播
为了测试,我也做了一个简单的UDP的广播代码;
//服务器端Scoket对象;
UdpClient client;
private IPEndPoint endpoint;
void Start()
{
//绑定UdpClient 端口,8866
client = new UdpClient(new IPEndPoint(IPAddress.Any, 8866));
//全网(255,255,255,255)
endpoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 0);
//每秒都发送
InvokeRepeating("Send",1,1);
}
void Send()
{
string dataStr = "[{\"x\":732.8001098632813,\"y\":1000.0156860351563},{\"x\":817.5443725585938,\"y\":379.5652160644531},{\"x\":956.8383178710938,\"y\":538.0902099609375}]";
byte[] SendData = System.Text.Encoding.UTF8.GetBytes(dataStr);
//发送,不需要异步。因为是广播,并且不关心有没有接受
client.Send(SendData, SendData.Length, endpoint);
}
备注:上面的代码就做了个简单功能:向全网每秒广播信息。端口号是:8866
二.游戏这边需要接受数据了。UDP异步接受
有几点需求:
1.单纯接受8866端口的数据就可以。
2.将byte数据转换成坐标数据。
3.接受到数据,才会触发游戏一些输入机制。所以需要异步接收(防止卡死)
unity这边的接受代码:
//服务器端Scoket对象;
private Socket ServerSocket;
private IPEndPoint Clients;
private IPEndPoint Server;
private EndPoint epSender;
//发送数据的字符数组
private byte[] SendData = new byte[1024];
//接受数据的字符数组
private byte[] ReceiveData = new byte[1024];
// Use this for initialization
void Start()
{
//服务器Socket对象实例化
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//服务器的IP和端口
Server = new IPEndPoint(IPAddress.Any, 8866);
//Socket对象跟服务器端的IP和端口绑定
ServerSocket.Bind(Server);
//客户端的IP和端口,端口 0 表示任意端口
Clients = new IPEndPoint(IPAddress.Any, 0);
//实例化客户端 终点
epSender = (EndPoint)Clients;
ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);
}
/// <summary>
/// 异步接受,处理数据
/// </summary>
/// <param name="iar"></param>
private void ReceiveFromClients(IAsyncResult iar)
{
int reve = ServerSocket.EndReceiveFrom(iar, ref epSender);
//数据处理
string str = System.Text.Encoding.UTF8.GetString(ReceiveData, 0, reve);
//每次接受到数据就传给ServerInput做处理。
ServerInput.GetInstance().AnalyzeJsonData(str);
ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);
}
下面这句是每次启动异步接受的代码。
ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);
下面的是:每次接受到数据后就将数据传给serverInput做处理。
//数据处理
string str = System.Text.Encoding.UTF8.GetString(ReceiveData, 0, reve);
//每次接受到数据就传给ServerInput做处理。
ServerInput.GetInstance().AnalyzeJsonData(str);
ServerInput代码:我们的协议是json格式的。所以这里做了个json的转换。和一个公开的事件:ServerInputEvent 每次接受到数据都会传给这个事件。游戏里哪里需要 直接注册这个事件就可以用了。
(注意:安卓的OpenOL的屏幕坐标系和unity的坐标系是上下反的。所以要处理下:Screen.height-(int)jObject[“y”])
public event Action<List<Vector2>> ServerInputEvent;
private static ServerInput instance = null;
public static ServerInput GetInstance() { return instance ?? new ServerInput(); }
ServerInput() { instance = this; }
/// <summary>
/// 处理服务器传来的json信息,传给事件
/// </summary>
/// <param name="jsonData"></param>
public void AnalyzeJsonData(string jsonData) {
try
{
List<Vector2> posList = new List<Vector2>();
JArray jsonObj = JArray.Parse(jsonData);
foreach (JObject jObject in jsonObj)
{
//Debug.Log(jObject["x"]);
//Debug.Log(jObject["y"]);
Vector2 pos = new Vector2((int)jObject["x"],Screen.height-(int)jObject["y"]);
posList.Add(pos);
}
if (ServerInputEvent != null)
ServerInputEvent(posList);
}
catch (Exception)
{
throw;
}
}
**最后附上test代码: 简单的打印到屏幕中
备注下(异步接受是子线程的,所以不能直接给UI赋值 所以转到主线程的Update.涉及到物理系统也一样)**
[SerializeField]
private Text text;
string str = null;
// Use this for initialization
void Start () {
//向ServerInputEvent事件注册
ServerInput.GetInstance().ServerInputEvent += attack;
}
private void Update()
{
text.text = str;
}
//这边写游戏内容的控制
void attack(List<Vector2> pos) {
str = "";
foreach (var item in pos)
{
print(item);
str = str + " " + "(" + item.x.ToString() + "," + item.y.ToString()+ ")";
}
}
最后附上项目:
链接:https://pan.baidu.com/s/1cK0UXC 密码:9gw0