leapmotion
Unity leapmotion开发实录(1)
本系列文章将会从一个初学者的脚步去讲解unity和leapmotion协同开发的一系列问题:
特:本人水平有限所以有错误请指正
本人也会引用一些代码 如果有所侵犯请联系删除
自2015.11.22开始周更
第一部分基-基础
首先,关于leapmotion 我想会看此类文章的应该都知道这是什么,无关将来这个产品的发展会如何,它作为虚拟现实或现实增强开发的练手是非常合适的。因为他有着非常舒适的开发环境,简单而成熟的SDK。最最重要的是结合unity/unreal,更是一种让你能在短时间之内通过引擎完成高质量手势识别应用的方法。
关于原理,和底层算法,因为代码封装完善,你根本不可能窥探到什么(当然肯定有人可以)。所以我的评价仅仅从实际效果出发先对leapmotion做出一个评价。
下图为leapmotion传感器的识别区域:
我们可以看到在y轴也就是高度上 leapmotion的识别距离真的是小的可怜(根据我实际测试不会超过50cm)也就是说如果不和其他硬件搭配
leapmotion的使用范围很窄
单单的桌面使用的话,基本没有什么实用价值原因有二:
1.桌面使用场景下,手势识别很累低效
2.leap仅仅依靠景深画面和算法得出的手势识别精度高,但是精确度差。也就是说可以识别你手势动作很微小的变化,但是对这些变化的呈现又表现出很大的偏差。
在和oculus dk2结合之后,leapmotion的实用性总算提高了一些,但是效果仍然不理想。
因此,后续leap在不推出新硬件的条件下,我十分不看好这个传感器的发展,未来的leap,要么被OVR等厂家收购,要么倒闭。
ok 有点跑题,绕回来。虽然他这不好那不好,但这是我们在市场上能获取到的最优秀的性价比最高的手势识别设备。以他和oculus来学习虚拟现实开发,是最合适不过的了
那废话说够了,开始吧
first 基础
准备阶段:
https://developer.leapmotion.com/getting-started/unity
当然是download everything___
准备工具包括:
unity(最好5.0以上版本)
http://unity3d.com/cn/get-unity/download
leapmotion应用&SDK
https://developer.leapmotion.com/
leapmotion unity core asset
https://developer.leapmotion.com/downloads/unity
(有朋友反应找不到leap core asset2.3下载地址在这里)
以上下载完毕之后接入leap使用visualizer检视和利用控制面板校准的过程我就不再赘述了,都有详细的引导。
那么既然是unity开发,c#自然是非常合适的了。所以对于刚刚接触unity的同学。了解unity的构成,以及c#脚本语言是非常重要的。
但是相比起来c#脚本教学可就多了去了,因此我只是做归纳总结。不作深入探究
下面我们简单的从leap的视角来看看unity/c#的一些特性:
头文件篇:
using UnityEngine;
using System.Collections;
using System;
using Leap;
命名空间类似其他语言中的库,所有脚本代码都要写在命名空间的类中。命名空间leap就是整个leapmotion脚本运作的核心。但是这和传统的c#有一些不同,例如在vs环境中的c#新建后
会产生以下引用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
从两段引用中我们也可以看出,c#语言在库上和某些早期的语言思路不太一致。至于详细的应用我们会在以后的更新中完整的介绍
正式代码篇:
unity:
public class NewBehaviourScript : MonoBehaviour {
//初始化函数,在游戏开始时系统自动调用。一般用来创建变量之类的东西。
void Awake () {
}
// 在所有Update函数前系统自动条用。一般用来给变量赋值。
void Start () {
}
// 每帧调用一次
void Update () {
}
//固定时间间隔调用一次
void FixedUpdate()
{
}
//每一个Update执行之后执行一次
void LateUpdate()
{
}
}
vs:
namespace consoleAPPlication1
{
class Program
{
static void Main(string[] args)//相当于c++中等main函数
{
//____code___//
}
}
}
我们看到 vs中需要自己定义命名空间 再以类的形式组织代码
而unity cs中只能继承于 MonoBehaviour这个命名空间,至于mono~是一种框架,鉴于初学贴的定位我们就不深入了。在此原则之下,只要没有碰到的C#script和传统的c#的区别我就一概不讲了。以免喧宾夺主。
至于unity的界面以及使用的教程有人写的水平比我高很多于是我就转载啦:
http://www.cnblogs.com/fortomorrow/archive/2012/10/28/unity01.html
总的来说,如果你有其他面对对象语言的基础。那么学习c#的成本将会非常低。如果你以前熟悉javascript/java,那么C#特性的异同在大多数情况下甚至可以忽略。
unity开发如果对实现效果不是极为苛刻那么开发的效率是非常高的。
如果你是个初学者,我会贴一段代码供大家熟悉c#特性的代码。供大家调试,修改。当然这些特性很多不会直接出现在脚本的编写中,但熟悉他们对于初学者来说对之后的工作有着非常大的好处
:
1.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _11
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.Hello();
p1.Age = 21;
p1.Name ="Kungge";
//p1.Nickname = "Dogegg";// 注意这个外部不能使用
Console.WriteLine(p1.Name );
//p1.Hello2();//这个外部也不可使用
p1.GiveNn("Gumzhep");
Console.ReadKey();
}
class Person
{
public int Age;
public string Name;
private string Nickname;
public void GiveNn(string nickname)
{
if (nickname == "Dogegg")
{
return;
}
this.Nickname = nickname;
}
private void Hello2()
{
}
public void Hello()
{
Console.WriteLine("HelloWorld");
Console.WriteLine("{0} {1} {2}",this.Age,this.Name,this.Nickname);//this.是我自己的
}
}
}
}
2.属性:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _11
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Age = 20;
Console.WriteLine(p.Age);
p.Age = -1;//非法值 无用
Console.WriteLine(p.Age);
p.Nage = 20;
Console.WriteLine(p.Nage);
/*p.Dage = 20;
Console.WriteLine(p.Dage );*/
//这将出现死循环
/* Person2 p2 = new Person2();
p2.Age = 20;//其是只读的
Console.WriteLine(p2 .Age);*/
Person3 p3 = new Person3();
p3.Age = 21;
Console.WriteLine(p3.Age);
Console.ReadKey();
}
class Person
{
private int age;
public int Age
{
set//set用来赋值
{
if (value < 0)//public字段和属性的区别 :属性可以进行非法设置值的判断
{
return;
}
this.age = value;//value是用户赋过来的值
}
get//get用来取值
{
return this.age;
}
}
private int nage;
public int Nage
{
set
{
this.nage = value;
}
get
{
return 18;//返回值是多少就是多少
}
}
private int dage;
public int Dage
{
set
{
this.Dage = value;//将出现死循环
}
get
{
return this.Dage;
}
}
}
/* class Person2
{
public int Age
{
get//这是只读的
{
}
}
}*/
class Person3
{
public int Age//编译器自动生成私有字段和set get代码块
{
get;
set;
}
}
}
}
3.练习一:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _11
{
class Program
{
static void Main(string[] args)
{
Robot r1 = new Robot();
r1.Name = "K1";
Robot r2 = new Robot();
r2.Name = "K2";
Robot r;
Console.WriteLine("请选择1:r1,2:r2");
string s = Console.ReadLine();
if (s == "1")
{
r = r1;
}
else
{
r = r2;
}
Console.WriteLine("Hello,I'm robot.");
r.Eat(5);
while (true)
{
string str = Console.ReadLine();
r.Speak(str);
}
Console.ReadKey();
}
}
class Robot
{
public string Name { set; get; }
private int full { set; get; }
public void SayHello()
{
Console.WriteLine("Hello,my name is {0}", Name);
}
public void Speak(string str)
{
if (str.Contains("你") && (str.Contains("名字") || str.Contains("姓名")))
{
this.SayHello();
}
else if (str.Contains("你") && str.Contains("女朋友"))
{
Console.WriteLine("我还没有了,要不你给我介绍一个");
}
else if (str.Contains("今天") && str.Contains("天气"))
{
Console.WriteLine("天气很好");
}
else if (str.Contains("你") && str.Contains("吃饭"))
{
Console.WriteLine("我已经吃过了");
}
else if (str.Contains("再见") || str.Contains("拜") || str.Contains("8"))
{
Console.WriteLine("拜,下次聊");
return;
}
else if (full <= 0)
{
Console.WriteLine("I'm hungry! Give some food.Please input the number.");
string str1 = Console.ReadLine();
this.Eat(Convert.ToInt32(str1));
}
else
{
Console.WriteLine("听不懂");
}
full--;
}
public void Eat(int food)
{
full = full + food;
}
}
}
4.对象的引用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _11
{
class Program
{
static void Main(string[] args)
{
int i = 10;//int,char,bool,datetime等类型都是值类型(value type),赋值的时候是传递拷贝
int j = i;
i++;
Console.WriteLine(j);
Person p1 = new Person(10);//普通的对象则是引用类型,赋值的时候是传递引用
Person p2 = p1;
p1.Age++;
Console.WriteLine(p2.Age);
IncAge(p2);
Console.WriteLine(p2.Age);//传递给函数也是引用传递
static void IncAge(Person p)
{
p.Age++;
}
Console.ReadKey();
}
}
class Person
{
public int Age
{
get;
set;
}
public Person(int age)
{
this.Age = age;
}
}
}
5.构造函数:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _11
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
Person p2 = new Person("K1");
Person p3 = new Person("K2",20);
Console.WriteLine("{0} {1}",p1 .Name,p1 .Age);
Console.WriteLine("{0} {1}", p2.Name, p2.Age);
Console.WriteLine("{0} {1}", p3.Name, p3.Age);
Console.ReadKey();
}
}
class Person
{
public int Age { set; get; }
public string Name { set; get; }
public Person()//构造函数和类名相同 可以重载
{
Name = "unknown";
Age = 1;
}
public Person(string name)
{
this.Name = name;
}
public Person(string name, int age)
{
this.Name = name;
this.Age = age;
}
}
}
6.继承:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 继承
{
class Program
{
static void Main(string[] args)
{
Chinese c1 = new Chinese();
c1.Name = "张三";
c1 .Age =21;
c1.Say();
c1.HaveTea();
American a1 = new American();
a1.Name = "Gump";
Japaniese j1=new Japaniese ();
//American a4=new Person ();//错误
Person p1 = c1;//这是正确的
//American a2=p1;//错误的
//American a3 =(American) p1;//强制转换错误
Person p2 = j1;
Person p3 = new Person();
Chinese c2 = (Chinese)p3;//想想为什么强制转换没有成功
Console.ReadKey();
}
}
class Person//所有的类都直接或间接继承Object类 其是所有类的基类
{
public int Age { set; get; }
public string Name { set; get; }
public void Say()
{
Console.WriteLine("{0}",Name);
}
}
class Chinese : Person
{
public string Tea { set; get; }
public void HaveTea()
{
Console.WriteLine("Chinese Tea is good!");
}
}
class American : Person
{
public void Westmeal()
{
Console.WriteLine("Make a difference.");
}
}
class Japaniese : Person
{
}
}
7.异常及异常处理
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 异常
{
class Program
{
static void Main(string[] args)
{
try
{
int i = Convert.ToInt32("asd");
Console.WriteLine("Convert 之后");
}
catch(Exception ex)
{
Console.WriteLine("数据错误:"+ex.message +ex.StackTrace);
Console.WriteLine("数据错误之后");
}
try
{
string str = DescAge(200);
}
catch(Exception ex)
{
Console.WriteLine("数据错误:"+ex.Message);
}
Console.ReadKey();
}
static string DescAge(int age)
{
if (age >= 0 && age <= 150)
{
return "正常";
}
else if (age > 150)
{
throw new Exception("神人啊");
}
else
{
throw new Exception("不正常");
}
}
}
}
8.常量,变量及static成员
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 常量,变量及static成员
{
class Program
{
public const int Week = 7;//const常量 常量名要大写
static void Main(string[] args)
{
const int Pi = 3;//不可变的量 注意这种用法
// Pi = 4;//
Console.WriteLine(3*Pi);
Person.height = 172;//注意
Person.Say();//不用new就能使用的方法static方法
Horse.Run();
//Person.Sing();//
Person p = new Person();
p.Sing();
p.Age =20;
//Rabbit r = new Rabbit();//
Rabbit .Weigth =8;
//Rabbit.Walk();
Rabbit.Eat();
Console.ReadKey();
}
}
public class Person
{
public static int height;
public int Age;
public static void Say()
{
Console.WriteLine(height);
//Console.WriteLine(Age);//在static成员中不能直接调用非static成员
//Person.Sing();
}
public void Sing()
{
Console.WriteLine(height);
Console.WriteLine(Age);
Person.Say();//在非static方法中可以调用static方法中的字段 方法
}
}
public class Horse
{
public static int Size;
public int Ability;
public static void Run()
{
Console.WriteLine(Person.height);
// Console.WriteLine(Person.Age);//
Person.Say();//在static方法中可以调用其它static方法的字段,属性,但不能调用非static的
//Person.Sing();
}
public void Leap()
{
Console.WriteLine(Person.height);
// Console.WriteLine(Person.Age);
Person.Say();
//Person.Sing();
}
}
static class Rabbit//这是一个静态类
{
public static int Weigth;
public string Name;
public static void Eat()
{
Console.WriteLine(Horse.Size);
// Console.WriteLine(Horse.Ability);
}
public void Walk()
{
Console.WriteLine(Horse.Size);
}
}
}
9.命名空间
(1)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using 命名空间.hr;
namespace 命名空间
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();//这是本命名空间的类
命名空间.wk.Person p2 = new 命名空间.wk.Person();
p2.Say();
Dog d = new Dog();//using 命名空间.hr
Convert.ToInt32("12");//using System
Console.ReadKey();
}
}
class Person
{
}
}
(2)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 命名空间.wk
{
class Person
{
public void Say()
{
Console.WriteLine("Hello");
}
}
}
(3)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 命名空间.hr
{
class Dog
{
}
}
10.索引
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 索引
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p[1]=172;
Console.WriteLine("{0} {1}",p[1],p[2]);
Console.WriteLine(p["Tom",1,2]);
Console.ReadKey();
}
}
class Person
{
public int Num1=168;
public int Num2=173;
public int this[int index]
{
set
{
if (index == 1)
{
Num1 = value;
}
else if (index == 2)
{
Num2 = value;
}
else
{
throw new Exception ("数据错误");
}
}
get
{
if (index == 1)
{
return Num1;
}
else if (index == 2)
{
return Num2;
}
else
{
throw new Exception("数据错误");
}
}
}
public string this[string name,int i1,int i2]
{
get
{
return name + i1 + i2;
}
}
}
}
动手是最重要的,在调试这些代码的过程中。你会深入的了解c#中的一些特性。
Now,just do it.
goodbye next week~
相关阅读
作为移动开发者,除了前期的团队组建这类基础工作,到了产品环节,将要面对包括开发、测试、发行、运营、变现的过程。鸟瞰整条产业链,应
在Android开发过程中,难免会接触到应用市场账号的申请工作,安卓应用上架的平台比较繁杂,比苹果的上架麻烦的多。想要上架应用,首先要
随着目前电子商务网站开发技术的迭代,电商网站的交互设计得到了很大程度的提升,可以认为现在的新型的商城平台都呈现出交互效果。由
A5创业网(公众号:iadmin5)7月5日报道,昨日上午,2018百度ai开发者大会在北京国家会议中心召开。此次大会百度都给大家带来了哪些内容?下
作为一个产业观察者,我被邀请参加了7月3日的百度AI开发者大会,更直观的看到了大家最近所热议的那个插曲。当天的细节大家在各种渠道