想做一个传感器鼠标控制器(手机陀螺仪控制PC端鼠标移动),Socket服务是其他大佬写的,PC端和Android同时请求服务生成ID然后PC端生成一个二维码(二维码信息就是那个ID),手机端进行扫描PC端二维码进行PC端和手机端的连接,成功后,手机端和PC端就可以通讯啦。将手机端的陀螺仪数据实时传给PC,PC端编写将陀螺仪数据实时转换成鼠标位置。(目前实现发送手机陀螺仪数据到PC端,PC端可以接受到数据,没进行和鼠标位置关联)
大佬给了个C#例子,我就是参考这个例子编写的代码。例子如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TPlantPlayerSocketTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket client1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket client2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private void btnConnect_Click(object sender, EventArgs e)
{
//两个客户端连接上同一个端口,产生两个会话
int nPort = 14020;
IPAddress ip = IPAddress.Parse("10.0.180.110");
IPEndPoint point = new IPEndPoint(ip, nPort);
client1.Connect(point);
client2.Connect(point);
//接收分配到会话id
byte[] buffer = new byte[1024 * 1024];
int n = client1.Receive(buffer);
string sSessonID1 = Encoding.Default.GetString(buffer, 0, n).Trim();
//接收分配到会话id
n = client2.Receive(buffer);
string sSessonID2 = Encoding.Default.GetString(buffer, 0, n).Trim();
//关联两个会话
string sSend = String.Format("Attach {0} {1}\r\n", sSessonID1, sSessonID2);
buffer = Encoding.Default.GetBytes(sSend);
client1.Send(buffer);
//接受关联到的SessionID
n = client1.Receive(buffer);
sSessonID1 = Encoding.Default.GetString(buffer, 0, n).Trim();
//接受关联到的SessionID
n = client2.Receive(buffer);
sSessonID2 = Encoding.Default.GetString(buffer, 0, n).Trim();
txtContent.Text = "Attach Success";
}
private void btnSend_Click(object sender, EventArgs e)
{
//一个会话给另外一个会话发送消息
byte[] buffer = Encoding.Default.GetBytes("Send json string for other!\r\n");
client1.Send(buffer);
//接受消息
byte[] buffer1 = new byte[1024 * 1024];
int n = client2.Receive(buffer1);
string sContent = Encoding.Default.GetString(buffer1, 0, n).Trim();
txtContent.Text = sContent;
/*byte[] buffer = Encoding.UTF8.GetBytes("json string for other!");
string sContent = Convert.ToBase64String(buffer) + "\r\n";
buffer = Encoding.Default.GetBytes(sContent);
client1.Send(buffer);
byte[] buffer1 = new byte[1024 * 1024];
int n = client2.Receive(buffer1);
sContent = Encoding.Default.GetString(buffer1, 0, n).Trim();
buffer1 = Convert.FromBase64String(sContent);
sContent = Encoding.UTF8.GetString(buffer1);
txtContent.Text = sContent;*/
}
}
}
下面是unity+PC端代码:
1.TcpClientHandler
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class TcpClientHandler : MonoBehaviour
{
Socket serverSocket; //服务器端socket
private string ClientIP = "10.0.180.110";//IP地址
IPAddress ip; //主机ip
IPEndPoint ipEnd;
string recvStr; //接收的字符串
string ScanSuccessRecvStr;
string sendStr; //发送的字符串
byte[] recvData = new byte[1024]; //接收的数据,必须为字节
byte[] ScanSuccessRecvData = new byte[1024];
byte[] sendData = new byte[1024]; //发送的数据,必须为字节
int recvLen = 0; //接收的数据长度
Thread connectThread; //连接线程
public Vector3 ServerVector;
private Queue<string> queue = new Queue<string>();//新建一个队列,用来存储服务器发来的数据
private void Start()
{
//InitSocket();
OnStringToVector("(0,1,2)");
}
//服务器初始化
public void InitSocket()
{
ip = IPAddress.Parse(ClientIP);
ipEnd = new IPEndPoint(ip, 14020); //服务器端口号
//开启一个线程连接
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
//接收服务器消息
void SocketConnet()
{
if (serverSocket != null)
serverSocket.Close();
//定义套接字类型,必须在子线程中定义
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接
serverSocket.Connect(ipEnd);
recvLen = serverSocket.Receive(recvData);
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
//recvStr = Encoding.Default.GetString(recvData,0,recvLen);
print(recvStr);
Debug.LogError("SocketConnect:"+recvStr);
queue.Enqueue(recvStr);
}
void SocketReceive()
{
SocketConnet();
//不断接收服务器发来的数据
while (true)
{
recvData = new byte[1024];
recvLen = serverSocket.Receive(recvData);
if (recvLen == 0)
{
SocketConnet();
continue;
}
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
queue.Enqueue(recvStr);
print(recvStr);
Debug.LogError("recvStr:"+recvStr);
//Debug.LogError("Vector3" + OnStringToVector(recvStr));
OnStringToVector(recvStr);
}
}
public void OnStringToVector(string p_sVec3)
{
Debug.LogError("^^^^6 " + p_sVec3);
if (p_sVec3 != "" && p_sVec3.Length != 0)
{
p_sVec3 = p_sVec3.Replace("(", "");
p_sVec3 = p_sVec3.Replace(")", "");
Debug.LogError("p_svec " + p_sVec3);
}
if (p_sVec3.Length <= 0)
{
ServerVector = Vector3.zero;
}
string[] tmp_sValues = p_sVec3.Trim(' ').Split(',');
if (tmp_sValues != null && tmp_sValues.Length == 3)
{
float tmp_fX = float.Parse(tmp_sValues[0]);
float tmp_fY = float.Parse(tmp_sValues[1]);
float tmp_fZ = float.Parse(tmp_sValues[2]);
ServerVector = new Vector3(tmp_fX, tmp_fY, tmp_fZ);
Debug.LogError("serverVector@@@ "+ServerVector);
}
}
private void OnApplicationQuit()
{
SocketQuit();
}
public void SocketQuit()
{
//关闭线程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后关闭服务器
if (serverSocket != null)
serverSocket.Close();
}
public void SocketSend(string sendStr)
{
//清空发送缓存
sendData = new byte[1024];
//数据类型转换
sendData = Encoding.UTF8.GetBytes(sendStr);
//发送
serverSocket.Send(sendData, sendData.Length, SocketFlags.None);
}
//返回接收到的字符串
public string GetRecvStr()
{
string returnStr;
//加锁防止字符串被改
lock (this)
{
if (queue.Count > 0)
{//队列内有数据时,取出
returnStr = queue.Dequeue();
return returnStr;
}
}
return null;
}
}
2.TcpServer
using UnityEngine;
using System.Collections;
using LitJson;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using UnityEngine.UI;
public class TcpServer : MonoBehaviour
{
public static TcpServer _instance;
TcpClientHandler tcpClient;
JsonData returnDataJson;
public RawImage RawImageRef;
public string returnData { get; private set; }
void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
// Use this for initialization
void Start()
{
//初始化网络连接
//tcpClient=new TcpClientHandler();
tcpClient = gameObject.AddComponent<TcpClientHandler>();
tcpClient.InitSocket();
}
// Update is called once per frame
void Update()
{
//returnDataHandle();//2018.12.5
returnData = tcpClient.GetRecvStr();
if (returnData != null)
{
RawImageRef.texture=BarcodeCam.BarCodeCamInstance.CreateQRCode(returnData,512,512);
Debug.LogError("RawImage ");
}
}
//服务器返回消息的处理
void returnDataHandle()
{
returnData = tcpClient.GetRecvStr();
print(returnData);
Debug.LogError("returnData:"+returnData);
if (returnData != null)
{
returnDataJson = JsonMapper.ToObject(returnData);
Debug.LogError("returnDataJson:" + returnDataJson);
switch (returnDataJson["cmd"].ToString())
{
//在此处解析Json,如有项目需要,最好在其他脚本编写,此处只为方便
}
}
else
{
Debug.LogError("This is null");
}
}
void OnApplicationQuit()
{
//退出时关闭连接
tcpClient.SocketQuit();
print("Quit");
}
public void closeC()
{//此处比较关键,因为在我们调试时,关闭程序Unity并不一定认为你是退出,所以上面代码也许不会执行,导致与服务器一直连接,Unity崩溃
tcpClient.SocketQuit();
print("closeC");
}
}
3.BarcodeCam
using UnityEngine;
using System.Collections;
using ZXing;
using ZXing.QrCode;
using System;
using ZXing.Common;
using ZXing.Rendering;
using System.Collections.Generic;
public class BarcodeCam : MonoBehaviour
{
public Texture2D encoded;
public static BarcodeCam BarCodeCamInstance;
void Awake()
{
BarCodeCamInstance = this;
}
void Start()
{
}
public Texture2D CreateQRCode(string QRCodeStr,int infowidth,int infoheight)
{
//设置二维码大小
encoded = new Texture2D(infowidth, infoheight);
//二维码边框
BitMatrix BIT;
//设置二维码扫描结果
string name = QRCodeStr;
Dictionary<EncodeHintType, object> hints = new Dictionary<EncodeHintType, object>();
//设置编码方式
hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
BIT = new MultiFormatWriter().encode(name, BarcodeFormat.QR_CODE, infowidth, infoheight, hints);
int width = BIT.Width;
int height = BIT.Width;
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
if (BIT[x, y])
{
encoded.SetPixel(y, x, Color.black);
}
else
{
encoded.SetPixel(y, x, Color.white);
}
}
}
encoded.Apply();
return encoded;
}
//void OnGUI()
//{
// GUI.DrawTexture(new Rect(100, 100, 256, 256), encoded);
//}
}
下面是unity+Android的代码
AccelerometerTest(手机加速仪应用)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AccelerometerTest : MonoBehaviour {
public Transform destroy; //声明挂载BlueClinderFX游戏对象的变量
public Transform flash; //声明挂载BlueClinderFX(1)游戏对象的变量
public Transform sphere; //声明场景中小球的游戏变量
Vector3 dir = Vector3.zero; //声明一个三维向量的变量
private float distance; //定义距离变量
private bool flag = false; //声明一个用来判断小球是否消失的标志位
private float mindistance = 4.0f; //定义小球和BlueClinderFX游戏对象的最小距离变量
private Vector3 currentPos;
private float speed = 5.0f;
public Text AccelerometerTempText;//加速度
void Update()
{
UpdateInput();
dir.x = Input.acceleration.x; //三维向量的x分量为加速度传感器的x分量
dir.z = Input.acceleration.y; //三维向量的z分量为加速度传感器的y分量
this.transform.GetComponent<Rigidbody>().AddForce(dir * 5);//为小球添加力的效果
distance = Vector3.Distance(sphere.position, destroy.position);//获取当前小球和BlueClinderFX的距离
//Debug.LogError("Distance"+distance);
AccelerometerTempText.text ="Accelerometer:"+ Input.acceleration.ToString();
if (distance <= mindistance)
{
sphere.position = destroy.position;//重置小球的当前位置
Invoke("spheredestroy", 0.1f); //在0.1秒后调用spheredestroy方法
flag = !flag; //标志位置反
}
if (flag)
{
//destroy.gameObject.SetActive(true);//BlueClinderFX
sphere.position = flash.position;//重置小球的当前位置
flash.gameObject.SetActive(true);//将BlueClinderFX(1)游戏对象的active置为true
Invoke("sphereflash", 1.0f);//在1秒后调用sphereflash方法
Invoke("flashreset", 10.0f);//在1秒后调用flashreset方法
flag = !flag;//标志位置反
}
}
void spheredestroy()
{
sphere.gameObject.SetActive(false);//将小球的active置为false(即为不可见)
}
void sphereflash()
{
sphere.gameObject.SetActive(true);//将小球的active置为true
}
void flashreset()
{
flash.gameObject.SetActive(false);//将BlueClinderFX(1)对象的active置为false
}
void UpdateInput()
{
if (Input.GetMouseButton(0))
{
Vector3 ms = Input.mousePosition;
// ms = Camera.main.ScreenToWorldPoint(ms);
Ray ray = Camera.main.ScreenPointToRay(ms);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
currentPos = hit.point;
}
Vector3 pos = Vector3.MoveTowards(this.transform.position, currentPos, speed * Time.deltaTime);
this.transform.position = pos;
}
}
}
GyroscopeTest(手机陀螺仪应用)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GyroscopeTest : MonoBehaviour {
bool draw = false;
bool gyinfo;
Gyroscope go;
public Text GyroscopeText;
void Start()
{
gyinfo = SystemInfo.supportsGyroscope;
go = Input.gyro;
go.enabled = true;
}
void Update()
{
if (gyinfo)
{
Vector3 a = go.attitude.eulerAngles;
a = new Vector3(-a.x, -a.y, a.z); //直接使用读取的欧拉角发现不对,于是自己调整一下符号
this.transform.eulerAngles = a;
this.transform.Rotate(Vector3.right * 90, Space.World);
draw = false;
GyroscopeText.text = "Gyroscope:"+ go.attitude.ToString();
GlobleData.CurrentGyroscopeValue = go.attitude.ToString();
}
else
{
draw = true;
GlobleData.CurrentGyroscopeValue = gameObject.transform.position.ToString();
}
}
void OnGUI()
{
if (draw)
{
GUI.Label(new Rect(100, 100, 100, 30), "启动失败");
}
}
}
AndroidTcpClientHandler
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class AndroidTcpClientHandler : MonoBehaviour
{
Socket serverSocket; //服务器端socket
private string ClientIP = "10.0.180.110";//IP地址
IPAddress ip; //主机ip
IPEndPoint ipEnd;
string recvStr; //接收的字符串
string sendStr; //发送的字符串
byte[] recvData = new byte[1024]; //接收的数据,必须为字节
byte[] sendData = new byte[1024]; //发送的数据,必须为字节
int recvLen = 0; //接收的数据长度
Thread connectThread; //连接线程
private Queue<string> queue = new Queue<string>();//新建一个队列,用来存储服务器发来的数据
private void Start()
{
// InitSocket();
}
//服务器初始化
public void InitSocket()
{
ip = IPAddress.Parse(ClientIP);
ipEnd = new IPEndPoint(ip, 14020); //服务器端口号
//开启一个线程连接
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketReceive()
{
SocketConnet();
//不断接收服务器发来的数据
while (true)
{
Debug.LogError("data$$4");
recvData = new byte[1024];
recvLen = serverSocket.Receive(recvData);
if (recvLen == 0)
{
SocketConnet();
continue;
}
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
queue.Enqueue(recvStr);
print(recvStr);
Debug.LogError("recvStr:"+recvStr);
}
}
public void ConnectChat(string ID1,string ID2)
{
byte[] buffer = new byte[1024*1024];
string sSend = string.Format("Attach {0} {1}\r\n",recvStr,GlobleData.ScannerServerID);
buffer = Encoding.Default.GetBytes(sSend);
serverSocket.Send(buffer);
Debug.LogError("buffer+"+buffer);
}
public void SendMessageToServer(string msg)
{
byte[] buffer = Encoding.Default.GetBytes("Send "+msg+"\r\n");
serverSocket.Send(buffer);
Debug.LogError("hah");
}
//接收服务器消息
void SocketConnet()
{
if (serverSocket != null)
serverSocket.Close();
//定义套接字类型,必须在子线程中定义
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//连接
serverSocket.Connect(ipEnd);
recvLen = serverSocket.Receive(recvData);
//recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
recvStr = Encoding.Default.GetString(recvData, 0, recvLen);
print(recvStr);
Debug.LogError("SocketConnect:" + recvStr);
queue.Enqueue(recvStr);
}
//private void OnApplicationQuit()
//{
// SocketQuit();
//}
public void SocketQuit()
{
//关闭线程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后关闭服务器
if (serverSocket != null)
serverSocket.Close();
}
public void SocketSend(string sendStr)
{
//清空发送缓存
sendData = new byte[1024];
//数据类型转换
sendData = Encoding.UTF8.GetBytes(sendStr);
//发送
serverSocket.Send(sendData, sendData.Length, SocketFlags.None);
}
//返回接收到的字符串
public string GetRecvStr()
{
string returnStr;
//加锁防止字符串被改
lock (this)
{
if (queue.Count > 0)
{//队列内有数据时,取出
returnStr = queue.Dequeue();
return returnStr;
}
}
return null;
}
}
AndroidTcpServer
using UnityEngine;
using System.Collections;
using LitJson;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.Text;
public class AndroidTcpServer : MonoBehaviour
{
public static AndroidTcpClientHandler _instance;
AndroidTcpClientHandler tcpClient;
JsonData returnDataJson;
bool isOnOnce=true;
public string returnData { get; private set; }
void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
// Use this for initialization
void Start()
{
//初始化网络连接
//tcpClient=new TcpClientHandler();
tcpClient = gameObject.AddComponent<AndroidTcpClientHandler>();
tcpClient.InitSocket();
}
// Update is called once per frame
void Update()
{
//returnDataHandle();
if (MouseToolLogic.MouseToolLogicInstance.IsScanSuccess)
{
if (GlobleData.ScannerServerID != "")
{
if (isOnOnce)
{
isOnOnce = false;
Debug.LogError("Connect ");
OnConnect();
}
}
}
}
private void OnConnect()
{
tcpClient.ConnectChat(tcpClient.GetRecvStr(),GlobleData.ScannerServerID);
}
public void OnSendMessageToServer()
{
tcpClient.SendMessageToServer(GlobleData.CurrentGyroscopeValue);
}
//服务器返回消息的处理
void returnDataHandle()
{
returnData = tcpClient.GetRecvStr();
//print (returnData);
if (returnData != null)
{
returnDataJson = JsonMapper.ToObject(returnData);
Debug.LogError("returnDataJson:"+returnDataJson);
switch (returnDataJson["cmd"].ToString())
{
//在此处解析Json,如有项目需要,最好在其他脚本编写,此处只为方便
}
}
}
void OnApplicationQuit()
{
//退出时关闭连接
tcpClient.SocketQuit();
print("Quit");
}
public void closeC()
{//此处比较关键,因为在我们调试时,关闭程序Unity并不一定认为你是退出,所以上面代码也许不会执行,导致与服务器一直连接,Unity崩溃
tcpClient.SocketQuit();
print("closeC");
}
}
GlobleData
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GlobleData
{
public static string ScannerServerID="";
public static string CurrentGyroscopeValue="";
}
MouseToolLogic
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseToolLogic : MonoBehaviour {
public static MouseToolLogic MouseToolLogicInstance;
public GameObject QRCodePanel;
public bool IsScanSuccess=true;
private void Awake()
{
MouseToolLogicInstance = this;
}
// Use this for initialization
void Start ()
{
}
void ScannerLogic()
{
if (GlobleData.ScannerServerID != "")
{
SetPanelActive(QRCodePanel,false);
}
else
{
SetPanelActive(QRCodePanel,true);
}
}
void SetPanelActive(GameObject obj,bool isActive)
{
obj.SetActive(isActive);
}
// Update is called once per frame
void Update ()
{
//ScannerLogic();
}
}
Cam(调用摄像头)
using UnityEngine;
using System.Collections;
using ZXing;
using UnityEngine.UI;
public class Cam : MonoBehaviour {
public Color32[] data;
private bool isScan; //是否能扫描
public RawImage cameraTexture;
public Text txt;
private WebCamTexture webCameraTexture;
private BarcodeReader barcodeReader;
private float timer = 0;
//public GameObject QRCodePanel;
IEnumerator Start()
{
barcodeReader = new BarcodeReader();
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
if (Application.HasUserAuthorization(UserAuthorization.WebCam))
{
WebCamDevice[] devices = WebCamTexture.devices;
string devicename = devices[0].name;
webCameraTexture = new WebCamTexture(devicename, 400, 300);
cameraTexture.texture = webCameraTexture;
webCameraTexture.Play();
isScan = true;
}
}
int width;
//屏幕横竖屏切换
void ScreenChange()
{
if (width == Screen.width)
return;
width = Screen.width;
if (width>Screen.height)
{
cameraTexture.transform.localEulerAngles = Vector3.zero;
}
else
{
cameraTexture.transform.localEulerAngles = new Vector3(0, 0, -90);
}
}
void Update()
{
Debug.LogError("hahhhhhhh");
if (isScan)
{
timer += Time.deltaTime;
if (timer >0.5f)// 0.5秒扫描一次
{
StartCoroutine(ScanQRcode());
timer = 0;
}
}
ScreenChange();
}
IEnumerator ScanQRcode()
{
data = webCameraTexture.GetPixels32();
DecodeQR(webCameraTexture.width, webCameraTexture.height);
yield return new WaitForEndOfFrame();
}
private void DecodeQR(int width, int height)
{
var br = barcodeReader.Decode(data, width, height);
if (br != null)
{
txt.text = br.Text;
//Debug.LogError("BR:"+br);
isScan = false;
GlobleData.ScannerServerID = br.Text;
}
}
}