1 偏向硬件方向的详细介绍
http://blog.csdn.net/kasama1953/article/details/51434295
2 偏向软件方向的,使用软件跟硬件交互,显示的屋里数据通过发送串口数据,控制虚拟的运动,自行车项目等等。如何发串口数据,这不是unity关心的,我们只要关心如何接受,并且如何使用它们
首先接受串口数据 using System.IO.Ports; 使用这个命名空间的方法
SerialPort 类
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Runtime.InteropServices;
using UnityEngine;
public class SerialPortData : MonoBehaviour
{
public bool Ismulti;
public int interval_ms = 30;
public string com = "COM2";
private List<byte> buffer = new List<byte>();
public int dataHead = 0xff;
private SerialPort MainPort;
private bool mainPortIsOpen;
//public GUIStyle mygui;
private byte[] ReceiveBytes = new byte[5];
private bool showstr;
public int speed_locate = 1;
public int btn_locate = 2;
public int rotation_locate = 3;
public float port_speedvalue;
public int port_rotationvalue;
public int port_btnvalue;
private string strport;
private float t1;
public static byte speed;
public static byte doorClose;
public int port_yugua;
[DllImport("user32")]
public static extern int MessageBox(int Hwnd, string text, string Caption, int iType);
private void OnApplicationQuit()
{
this.mainPortIsOpen = false;
this.MainPort.Close();
}
private void OnGU1I()
{
//float x = Camera.mainCamera.ViewportToScreenPoint(new Vector3(0f, 0f, 0f)).x;
//if (this.showstr)
//{
// GUI.Label(new Rect(x, (float)(Screen.height - 50), 700f, 50f), "Port: " + this.com + " Data: " + this.strport, this.mygui);
//}
GUIStyle bb = new GUIStyle();
bb.normal.background = null; //这是设置背景填充的
bb.normal.textColor = new Color(1, 0, 0); //设置字体颜色的
bb.fontSize = 30; //当然,这是字体颜色
GUI.Label(new Rect(30, 20, 800, 400), "data:"+this.strport, bb);
}
private void ProcessMsg()
{
this.strport = this.ReceiveBytes[0].ToString() + " " + this.ReceiveBytes[1].ToString() + " " + this.ReceiveBytes[2].ToString() + " " + this.ReceiveBytes[3].ToString();
this.port_speedvalue = this.ReceiveBytes[this.speed_locate]; // 速度
//Debug.Log("");
this.port_rotationvalue = this.ReceiveBytes[this.rotation_locate]; // 播放
this.port_btnvalue = this.ReceiveBytes[this.btn_locate]; // 开关车门
this.port_yugua = this.ReceiveBytes[4];// 获取第五位
Debug.Log(this.port_yugua);
Array.Clear(this.ReceiveBytes, 0, this.ReceiveBytes.Length);
}
private void Start()
{
try
{
this.MainPort = new SerialPort(this.com, 0x2580, Parity.None, 8, StopBits.One);
this.MainPort.Open();
}
catch (Exception exception)
{
MessageBox(0, exception.Message + " I'm open" + this.com, null, 0x40);
this.MainPort = null;
Application.Quit();
}
if ((this.MainPort != null) && this.MainPort.IsOpen)
{
this.mainPortIsOpen = true;
}
else
{
this.mainPortIsOpen = false;
}
}
public void WritePortData(string dataStr)
{
if (this.mainPortIsOpen)
{
this.MainPort.Write(dataStr);
}
}
private void Update()
{
if (this.mainPortIsOpen)
{
this.t1 += Time.deltaTime;
// 30ms 算一次
if ((this.t1 * 1000f) >= this.interval_ms)
{
this.t1 = 0f;
byte[] buffer1 = new byte[20];
int length = 0;
try
{
length = this.MainPort.Read(buffer1, 0, 20); // read 放到buf1中,然后将buf1拷贝到destinationArray中,
//然后在buf追加destinationArray。当buf长度超过5,解析给ReceiveBytes,清空buf,重新读取
Debug.Log("Length " + buffer1.Length+" "+buffer1[2]);
}
catch (Exception)
{
MessageBox(0, "Port breaked! Plaese reconnect!!! I'm " + this.com, null, 0x40);
this.MainPort = null;
Application.Quit();
}
byte[] destinationArray = new byte[length];
Array.Copy(buffer1, destinationArray, length);
this.buffer.AddRange(destinationArray);
if (this.buffer.Count >= 5)
{
// Debug.Log("count is out 5");
if (this.buffer[0] == this.dataHead)
{
this.buffer.CopyTo(0, this.ReceiveBytes, 0, 5);
this.ProcessMsg();
this.buffer.Clear();
}
this.buffer.Clear();
}
// this.MainPort.Write(new byte[] { 0xff, speed, doorClose }, 0, 3);
}
if (Input.GetKeyDown(KeyCode.F5))
{
this.showstr = !this.showstr;
}
}
}
}
获取数据,然后控制物体运动,一般运动使用第三人称脚本
using UnityEngine;
using System.Collections;
/**
* @Author : www.xuanyusong.com
*/
[RequireComponent(typeof(CharacterMotor))]
[AddComponentMenu("Character/FPS Input Controller")]
public class FPSInputController : MonoBehaviour {
private CharacterMotor motor ;
// Use this for initialization
void Awake () {
motor = GetComponent<CharacterMotor>();
}
// Update is called once per frame
void Update () {
// Get the input vector from kayboard or analog stick
Vector3 directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
if (directionVector != Vector3.zero) {
// Get the length of the directon vector and then normalize it
// Dividing by the length is cheaper than normalizing when we already have the length anyway
var directionLength = directionVector.magnitude;
directionVector = directionVector / directionLength;
// Make sure the length is no bigger than 1
directionLength = Mathf.Min(1, directionLength);
// Make the input vector more sensitive towards the extremes and less sensitive in the middle
// This makes it easier to control slow speeds when using analog sticks
directionLength = directionLength * directionLength;
// Multiply the normalized direction vector by the modified length
directionVector = directionVector * directionLength;
}
// Apply the direction to the CharacterMotor
// 此处加入旋转的代码
motor.inputMoveDirection = transform.rotation * directionVector;
motor.inputJump = Input.GetButton("Jump");
}
}
如果通过串口数据,加入旋转代码:
spdata = GameObject.Find("myfirst").GetComponent<SerialPortData>();
float RotationValue = ClampFloat(spdata.port_rotationvalue, vrCenter) * vrDir;
transform.Rotate(new Vector3(0, RotationValue * vrRotateSpeed * 0.01f, 0)); //旋转轴是Y轴(向上)
motor.inputMoveDirection = transform.rotation * directionVector * vrMoveSpeed * Time.deltaTime * 12;
float ClampFloat(float value, float center)
{
return value - center;
}
这是一种情况,根据串口旋转,还有就是根据路径点旋转,读取每个路径点,旋转注视
private Transform[] Road_T; 保存所有路径点
Road_T = GameObject.FindGameObjectWithTag(name).GetComponentsInChildren<Transform>(); 获取所有路径点,保存
private void RotateG() {
if(Vector3.Distance(this.transfrom.position,Road_T[count].position)<5f){
canMove = true;
}
if (canMove) {
canMove = false;
if (count == Road_T.Length - 1) {
count = Road_T.Length - 1;
return;
}
count++;
}
this.transform.rotation = Quaternion.Lerp(this.transform.rotation,Quaternion.LookRotation(Road_T[count].position-this.transform.position),5*Time.deltaTime);
}
是起到平滑过渡的效果
但你要去控制时间 tim.time 或 time。
datetime 才能看出平滑过渡效果来
LookRotation 旋转插值
此函数作用是生成一个四元数表示的三维朝向,然后可以直接把这个朝向赋给游戏对象来变更其朝向,也可以通过线性插值(Quaternion.Slerp 和 Quaternion.Lerp)来实现游戏对象从当前朝向转到这个新生成的朝向上来
static function LookRotation (forward : Vector3, upwards : Vector3 = Vector3.up) : Quaternion
现在来看 LookRotation 的两个参数,第一个参数 forward,是一个三元组,也就是三个浮点数的组合,这个三元组可以确定世界坐标系下的一个点,从世界坐标系的坐标原点到这个定点就构成了一个三维空间矢量,当我们忽略这个矢量的长度时,它就退化为一个纯粹的方向指示,换句话说,这第一个参数 forward 确定了一个世界坐标系下的方向,而这个方向就是物体转动后 +z 轴所要指向的方向;第二个参数 upwards,也是个三元组(之前没看懂就是没看懂在这个参数上,一致闹不明白这个三元组是干啥用的),这个三元组同样可以确定一个世界坐标系下的方向,物体转动后 x 轴必须与这个方向垂直(如果转动前物体的x轴不满足此条件,那么物体除了改变朝向外还会绕 z 轴旋转以确保转动结束后 x 轴与此方向垂直)。
示例代码:
using UnityEngine;
using System.Collections;
public class LookAtRotation : MonoBehaviour {
public Transform cube;
public Transform target;
public Vector3 v;
// Use this for initialization
public enum Direc {
UP= 1,
Forwad=2,
}
public Direc direc;
void Start () {
}
// Update is called once per frame
void Update () {
if (direc == Direc.Forwad) v = Vector3.forward;
else v = Vector3.up;
cube.rotation = Quaternion.LookRotation(target.position-cube.position,v);
Debug.DrawLine(Vector3.zero,cube.forward,Color.blue);
Debug.DrawLine(Vector3.zero,cube.right,Color.red);
Debug.DrawLine(Vector3.zero,cube.up,Color.green);
}
}
补充:
运行一段时间发现,串口通信会卡死。。。就是当接受不到数据的时候会卡死! 目测是线程堵死了,看了Read半天也没有发现这个API是否是堵塞,不管了,直接放到子线程处理
over