2017-12-21 18:23:27 hanxiaoyuan32 阅读数 3631
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

Unity3D

Unity基本操作

Unity基本单位为米,ue4是厘米

Rotation 为度,监事面板是角度,代码里计算的结果是弧度

Scale的单位是倍数。负数为左右镜像

 

创建工程

必要文件夹:

Sences

Scripts

Prefabs

 

工程结构

 

Assets所有素材都在里面,迁移必须

Library临时文件库,迁移工程时不拷贝,临时生成

ProjectSettings 项目设置-projecversion 项目版本号,迁移必须

Temp缓存文件,可以不拷贝。

Meta文件都是unity生成的导入配置信息,例如图片的分辨率,压缩方式,版本控制时,例如svn一般不上传。

X轴旋转到正负90度,会发生万向死锁

组成

Scene(场景)

编辑游戏中所有的内容

右键控制视角,右键+w/s/a/d,对应视角移动操作。

按住鼠标中间切换移动,松开切换回来

Game(游戏窗口)

游戏中真正显示的内容

Project(资源窗口)

包含项目中所有的资源,对应工程下Asset目录

右键-show in exploder  打开对应文件夹

Hierachy(对象实例化的窗口)

游戏世界中所包含的内容。

Inspector(信息面板、检视面板)

Console(控制台)

Debug.Log();

Unity中视觉窗口所有内容都称为Gameobject

坐标

Unity2d的(00)点是game窗口左下角。3d使用左手坐标系。

相对坐标和绝对坐标

库函数

UnityEngine->unity库。

class只有继承了MonoBehaviour才能挂到gameobject身上

DeBug

日志输出

Log 输出,黑色

LogError 打印红色日志,错误

LogWarning 打印黄色警告日志

属性

name属性是当前脚本所在游戏物体的名字

警告处理

1、如果出现了the referenced(引用) script  on this Behaviour is missing ,选中后下发有描述,一般此错误有两种可能,一是脚本被删除,二是脚本名或类名被改变了。

2、如果脚本丢失,建议先删除再重新添加。

3、脚本名必须和类名一致

错误处理

error CS0103: The name `XXX' does not exist in the current context xxx类不存在

error CS1501: No overload for method `xxxx' takes `n' arguments  xxxx方法参数数量有误

unity对大小写敏感。

NullReferenceException(异常): Object reference not set to an instance of an object空引用异常

error CS0266: Cannot implicitly convert type `UnityEngine.Component' to `UnityEngine.Transform'. An explicit conversion exists (are you missing a cast?) 不能转换类型

消息函数

不是主动调用,通过消息机制调用的函数。例如start()update()

SendMessage()发送消息的方法,所有的gameobject对象都可以调用。但不要使用sendmessage,因为效率很低。

生命周期

Awake() 脚本实例化时调用,一般用于初始化,脚本开始只执行一次,Awake在初始化之前调用,在Awake中调用不到其他函数,因为可能还没有初始化。

Start() 脚本第一次启用update前调用(Awake之后执行),也用于初始化,但不同与Awake后于Awake调用

Onenble当组件被激活的时候执行(脚本激活时)。

Ondisable当组件被失活的时候执行。

Update() 运行时,每帧调用。屏幕刷新一遍为一帧,人眼为24

FixedUpdate() update()的帧长不同,FixedUpdate先执行,它的每帧时间完全固定0.02,每帧时间可以在unity中设置,edit中,倒数第三个选项,主要应用于物理受力处理

OnDestroy() 该脚本被移除时调用,同时对应物体被删除时也会调用。(其实还是脚本被删除时调用,删除物体同时也删除了脚本,先删除组件后,再删除物体就不会触发。)

OnGUI(),每一帧调用,和update相同,负责绘制屏幕(game窗口),使用的APIGUI 的类。

物理生命周期

OnCollisionEnter(Collision); 当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionEnter将被调用

OnCollisionExit(Collision)当此collider/rigidbody停止触发另一个rigidbody/collider时,OnCollisionExit将被调用。

OnCollisionStay(Collision)当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionStay将会在每一帧被调用。

OnTriggerEnter 

Collider(碰撞体)进入trigger(触发器)时调用OnTriggerEnter

OnTriggerEnter2D 

当另一个对象进入到这个对象附加的触发碰撞器时发送消息(仅2D物理)。

OnTriggerExit 

Collider(碰撞体)停止触发trigger(触发器)时调用OnTriggerExit

OnTriggerExit2D 

当另一个对象离开附加在这个对象的触发碰撞器时发送消息(仅2D物理)。

OnTriggerStay 

当碰撞体接触触发器时,OnTriggerStay将在每一帧被调用。

OnTriggerStay2D 

当另一个对象停留在这个对象附加的触发碰撞器内时,每帧发送消息(仅2D物理)。

预制体prefab

场景内容是临时存在的,预制体是永久存在的,所以,场景内的物体拖不到预制体的代码中。

创建预制体

将物体直接拖到资源窗口,就能自动创建预制体

游戏中使用预制体的物体,最上方或多出三个属性:select(选中当前使用预制体的文件),apply(应用修改的数据到预制体,所有使用此预制体的物体都会改变),revert点击会恢复默认的预制体数据。

 

加载预制体

加载预制体,就必须把预制体放在Resources目录下,通过Resources.Load(路径)获取预制体,然后通过Instantiate()实例化。

禁忌:禁止直接使用预制体,因为这样会在运行期间直接修改预制体的数据,停止运行后预制体数据不会还原

Resources目录

该目录属于unity官方指定目录,必须使用此名字,存放资源使用。

一般存放预制体,贴图,音效等内容。

加载通过Resources.Load(“路径及文件名”),或者Resources.Load<T>(路径及文件名);

路径根起点默认为Resources,因此不用写Resources

例如:Resources.Load<GameObject>(“A”);

加载后需要通过实例方法(Instantiate())添加到世界中。

Instantiate(original: Object, position: Vector3, rotation: Quaternion) 克隆原始物体并返回克隆物体。

Resurces.load是堵塞性加载,加载内容时程序会一直停在这里,加载完成时才会继续往下执行。

Resurces.load加载后,不使用了需要释放掉,否则会一直在内存中加载,使用Resources.UnloadAsset(变量名); 随后变量名一定要置空,否则该变量会变成一个未知指向的野指针。

不要在update中使用Resurces.load

动态资源加载(异步资源加载)

Resources.LoadAsync();异步加载。异步加载不会堵塞主线程

返回ResourceRequest类型的对象,该对象继承于AsynOperation

AsynOperation中有一个progress进度函数,该值为0-1,常用于场景切换的进度条。

AsynOperation中有属性isDone,是否加载完成

加载完成的资源在ResourceRequest的对象.asset字段中

异步加载常常配合协程使用。

遇到函数Async结尾一定都是异步,sync肯定是同步的。

场景切换

场景类Application类(早期版本使用)

Application.Quit();退出场景,结束游戏

Application.Load ();已弃用。

SceneManager

使用要先using unityEngine.SceneManager

SceneManager.loadScene(场景索引);

加载场景的异步加载

SceneManager.LoadSceneAsync(场景索引);返回值是asyncOperation类型,也有progress

异步加载完后会自动跳转场景,不会等待指令。

asyncOperationallowSceneActiveation属性改为false后,就不会加载完成后自动跳跃了,但此时进度也会永远变不了100%,最大停留在0.9的位置,isDone永远为false,发送跳跃指令后才会完成。

工程与工程之间的资源迁移

导出,再导入

Export package,系统会自动选中所有关联资源

2014-12-24 10:52:43 caoboya 阅读数 509
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

欢迎来到unity学习unity培训unity企业培训教育专区,这里有很多U3D资源U3D培训视频U3D教程U3D常见问题U3D项目源码,我们致力于打造业内unity3d培训、学习第一品牌。

一、键盘判断。    
       GetKey:当通过名称指定的按键被用户按住时返回true
       GetKeyDown:当用户按下指定名称的按键时的那一帧返回true。
       GetKeyUp:在用户释放给定名字的按键的那一帧返回true。
       GetAxis(“Horizontal")和GetAxis(“Verical”) :用方向键或WASD键来模拟-1到1的平滑输入
       代码:
       if (Input.GetKey(“up”)) {
           print("up arrow key is held down");
       }
       if (Input.GetKey(“down”)) {
           print("down arrow key is held down");
       }
       If(Input.GetKeyDown(KeyCode.Escape)){
            print(“按下Esc键”);
       }
       If(Input.GetKeyDown(KeyCode.A)){
            print(“按下A键”);
       }
       If(Input.GetKeyUp(KeyCode.Escape)){
           print(“松开Esc键”);
       }
       If(Input.GetKeyUp(KeyCode.D)){
           print(“松开D键”);
       }
       GetAxis是float型,不能用if判断
       print (Input .GetAxis ("Horizontal"));
       print (Input.GetAxis ("Vertical"));
二、鼠标判断。
       GetButton:根据按钮名称返回true当对应的虚拟按钮被按住时。
       GetButtonDown:在给定名称的虚拟按钮被按下的那一帧返回true。
       GetButtonUp:在用户释放指定名称的虚拟按钮时返回true。
       if(Input.GetButton("Fire1")){
              print(“按下鼠标左键”);
       }
       if (Input.GetMouseButton(0)) {
             Debug.Log("按下鼠标左键");
       }
       if (Input.GetMouseButton(1)) {
             Debug.Log("按下鼠标右键");
       }
       if (Input.GetMouseButton(2)) {
             Debug.Log("按下鼠标中键");
       }
三、项目工程分层设计。
       Scenes——  存放场景
       Scripts——  存放脚本
       Resources——  资源包
       Textures——  贴图
       Materials——  材质(主要为.mat文件)
       Audios——  声音
       Models——  模型(存放FBX等文件)
四、Mono Develop脚本编辑器介绍。
       (Unity 自带脚本编辑器)
  1、Unity3d目前支持三种语言的脚本程序,包括c#,JavaScript,boo;其中使用最多为c#。
       注意:
       (1)项目运行过程中的修改不会保存
       (2)脚本只能依附于游戏对象或由其他脚本调用才能运行
       (3)一个脚本可以放在多个游戏对象上面,是多个实例
       (4)一个脚本的多个实例和其他脚本之间互不干扰
  2、初始化不要放在构造函数中,而是放在start()方法中。
  3、放到游戏对象中的脚本(实例化)可以在Inspector中修改属性,gett写法属性不被识别,直接public字段就能当属性用,不写修饰符就是私有private
五、创建、克隆、销毁游戏对象。
       程序(动态)创建游戏对象
       eg:
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
       cube.name = "cube1";//设定名字
       cube.renderer.material.color = Color.red;
      程序(动态)克隆对象
       eg:
       GameObject obj = (GameObject)Instantiate(cube);
       程序(动态)销毁对象
       eg:
       Destroy(obj,1);
      特点:
  1、动态创建出来的对象运行时在Hierarchy中可以看到。
  2、克隆游戏对象产生复制对象的效率高,调用instantiate来生成对象,Destroy(obj)是立即销毁游戏对象。
  3、动态添加脚本的方法:只要把脚本名称传给AddComponen即可
六、给游戏对象添加名称、刚体、碰撞器。
  1、给游戏物体添加名为FoobarScript的脚本
       GameObject.AddComponent ("FoobarScript");
  2、给游戏物体添加刚体
       Rigidbody  rb = GameObject.AddComponent ("Rigidbody");
  3、给游戏物体添加球体碰撞器
       SphereCollider  sc = GameObject.AddComponent ("SphereCollider");
七、常用核心类。
  (1)通过名称来查找:
       GameObject  player = new GameObject("Player");
       GameObject  go=GameObject.Find(“Player”);
  (2)通过tag标签获取单个游戏对象:
       GameObject  go=GameObject.FindWithTag(“Player”);
       GameObject go=GameObject..FindGameObjectWithTag (“Player”);
  (3)通过游戏标签获取多组游戏对象:
       GameObject[]  go=GameObject.FindGameObjectsWithTag (“Player”);
八、Time类。
       属性: deltaTime
       说明:
       方法Update(): 受当前渲染效率的影响,有时快有时慢,帧率会变化,Update被调用的时间间隔就发生变化,Time. deltaTime获得自上次Update一来经历的时间,只应该在Update()中使用deltaTime ,OnGUI、FiexedUpdate等里面不要用。
       按下A键,游戏物体向左移动;按下D键,游戏物体向右移动                 
       float move_h=0;
       if (Input.GetKey (KeyCode.A)) {
             move_h-=Time.deltaTime;
       }
       if (Input.GetKey (KeyCode.D)) {
             move_h+=Time.deltaTime;
       }
       transform.Translate(new Vector3(move_h,0,move_v));
九、Random类(随机数)。
       float a=Random.value;
       int b=Random.Range(0,100)    包括最大和最小
       float c=Random.Range(0.0f,1.0f);   包括最小但不包括最大
十、Yield。
       Yield语句是一种特殊类型的Return(返回)语句,它可以确保函数在下一次被执行时,不是从头开始,而是从Yield语句处开始。
       可以实现将一段程序延迟执行或者将其各个部分分布在一个时间段内连续执行。
       eg:
       void Start () {
           print("Start开始");
           StartCoroutine(Do());
           print("Do调用后");
       }
       IEnumerator Do()
       {
           print("Do开始");
           yield return  new WaitForSeconds(3.0f);
           print("暂停3秒后");
       }
十一、消息传递函数。
       Message相关有3条指令:
       SendMessage ("函数名",参数,SendMessageOptions) //GameObject自身的Script
       BroadcastMessage ("函数名",参数,SendMessageOptions)  //自身和子Object的Script
       SendMessageUpwards ("函数名",参数,SendMessageOptions)  //自身和父Object的Script
2013-01-12 14:52:45 borsyu 阅读数 7113
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    不得不说,unity3d是一个解放生产力的游戏引擎,自带了各种编辑器,可以进行一系列的可视化操作。

需要注意的是,unity3d适合FPS游戏,物理游戏等中小型的游戏,并不太适合MMO开发。

    从最开始接触unity3d,到了解大致内容,能上手开发,自己断断续续用了半个月时间。期间走了不少弯路,

总结了一下一个自己倒过头来觉得适合一些没有接触过unity3d的朋友的学习路线:


此过程假设学习者:

        1. 有一定图形学基础,比如清楚3D平移旋转等操作,四元数基本原理,对纹理,材质,灯光等有基本了解。

        2. 开发语言不是障碍,即采用何种语言进行开发不是问题。

        3. 阅读英文艺术文档没有障碍

对于1,如果是计算机专业毕业,一般找一本图形学的书籍看半天足够了。

对于2,unity3d支持C#,Javascript,Boo三种脚本语言开发,可以任选一种。

学习路线也可以根据实际情况任选。

学习路线1:

       1.  手册manual第一部分通读,并熟悉unity3d环境(半天)

       2.  通读手册脚本指南中的overview部分(半天)

       3.  官网的例子学习,3DPlatformTutorial(一周)


学习路线2:

       1. 手册manual第一部分通读,并熟悉unity3d环境(半天)

        2. 照书学,理论结合实例,如果基础稍弱,且想学想做的游戏有不少2D元素,可以采用《Unity 3.x Game Development beginner》一书,                  

        若基础稍好一点点,可以采用《Unity.3.x.Game.Development.Essentials》一书。PS:这2本书都有英文电子版可以下载。(一周)


OK,就这么简单,其实只要几天,就足够上手开发了。认真做完这几步,基本上已经能够应付大部分游戏开发内容了,剩下的就可以边做边熟悉了。


2019-01-22 19:33:49 ugfdfgg 阅读数 606
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

               

// Use this for initialization
 void Start ()
 {
   string path="";
   if(Application.platform==RuntimePlatform.Android)
   {
    path=Application.persistentDataPath;
   }
   else if(Application.platform==RuntimePlatform.WindowsPlayer)
   {
    path=Application.dataPath;
   }
   else if(Application.platform==RuntimePlatform.WindowsEditor)
   {
    path=Application.dataPath;
   }
  
   string configip=LoadFile(path,"test.txt");
   if(configip!="error")
   {
    gameObject.GetComponent<UILabel>().text="read:"+configip;
   }
   else
   {
    createORwriteConfigFile(path,"test.txt","192.168.200.252");
    string str=LoadFile(path,"test.txt");
    gameObject.GetComponent<UILabel>().text="create:"+str;
   }
 }
 /// <summary>
 /// 在指定位置创建文件   如果文件已经存在则追加文件内容
 /// </summary>
 /// <param name='path'>
 /// 路径
 /// </param>
 /// <param name='name'>
 /// 文件名
 /// </param>
 /// <param name='info'>
 /// 文件内容
 /// </param>
 private void createORwriteConfigFile(string path,string name,string info)
 {
   StreamWriter sw;          
   FileInfo t = new FileInfo(path+"//"+ name);          
   if(!t.Exists)          
   {            
    sw = t.CreateText();
   }          
   else      
   {
    sw = t.AppendText();         
   } 
   sw.WriteLine(info);
   sw.Close();
   sw.Dispose();
 }
 /// <summary>
 /// 删除文件
 /// </summary>
 /// <param name='path'>
 /// Path.
 /// </param>
 /// <param name='name'>
 /// Name.
 /// </param>
 void DeleteFile(string path,string name)
 {
   File.Delete(path+"//"+ name);
 } 
 /// <summary>
 /// 读取文件内容  仅读取第一行
 /// </summary>
 /// <param name='path'>
 /// Path.
 /// </param>
 /// <param name='name'>
 /// Name.
 /// </param>
private string LoadFile(string path,string name)   
{     
   FileInfo t = new FileInfo(path+"//"+ name);          
   if(!t.Exists)
   {
    return "error";
   }
   StreamReader sr =null;    
   sr = File.OpenText(path+"//"+ name);
       string line;    
  while ((line = sr.ReadLine()) != null)    
  {    
break;
  }
   sr.Close();
   sr.Dispose();
   return line;
}      


<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

2014-09-18 00:08:53 qinyuanpei 阅读数 27220
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

        各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在前一篇文章中,我们研究了Android平台上Unity3D的手势操作并在之前的基础上实现了手势旋转、放缩等功能。今天呢,我们继续来研究Unity在Android平台上扩展的内容。众所周知,Unity3D是一个强大的跨平台游戏引擎,和大多数喜欢Unity的朋友一样,博主在体验了Unity强大的跨平台能力后,被深深地震撼了,试想以前我们如果要开发一款游戏的话,我们需要对DX、OpenGL等图形库有足够的了解,由于游戏对性能的严格要求,诸如Unreal、CryEngine等顶级的商业游戏引擎通常都是使用C/C++这种底层的语言来开发,使得许多开发者望而却步。而此时此刻,得益于Unity3D强大的跨平台能力,博主可以用自己喜欢的C#语言来编写游戏,这无疑说明博主和成千上百使用Unity的开发者一样,我们正处于一个商业化引擎逐渐成熟的时代,作为开发者的我们是幸福的。

       

       记得"仙剑之父“姚壮宪作为评委参加Unity亚洲区的比赛时曾经感慨道:"我学生时也是痴迷于自己不断钻研游戏开发,从各种小游戏和小工具做起,并不断的回头优化改良以前的作品,积累经验技巧。那时候没有商业引擎可以用,需要自己给自己做底层引擎。现在的年轻人是幸福的,有Unity这样向大众公开的引擎可以学习和使用,可以把精力更多地专注在游戏作品本身的创作,更应该把握这样的环境"。所以相比游戏界的前辈们用QBasic来写《仙剑奇侠传》这样的游戏作品,我们这代人无疑要幸福得多,可是我们这代人身上的担子却并不轻啊。如今的时代是一个多元化的时代,无论是在应用开发领域还是游戏开发领域,目标用户平台多样化成为我们不得不去面对的问题。以目前国内的移动手机平台为例,主流的移动手机平台就有IOS、Android、Window Phone三种。尽管从理论上来讲,我们可以不用写一行Object-C或者Java代码就可以开发出IOS、Android上的应用,可是如果我们需要和该平台的某些接口进行交互的时候,我们就不得不考虑Unity和这些平台的对接。举一个最为常见的例子,大家都知道在移动平台上流行一种应用内付费的模式,可是Unity并没有为我们提供相应的API,在IOS平台上由于苹果应用商店的唯一合法性,我们想在该平台上实现应用内付费就必须使用苹果官方提供的SDK,而苹果官方主推Object-C,所以我们不可避免地要和Object-C打交道。同样地,在Android平台上由于Android的开源导致Android设备的多样性、应用商店的多样性,我们选择将自己的应用上架的时候,同样面临着和Java或者C++(JNI)打交道的问题。所以,我们今天就来研究下Unity和其它平台的交互调用的问题,由于博主手头上只有一部用了很长时间的Android手机,所以我们今天就以Android平台为例,探讨下Unity和Android的交互吧!

       Unity和Android交互通常有两种方式:

       1、Unity调用为Android平台编写的插件

       2、将Unity项目导出为Android项目,然后编写Android程序

       这两种方式在实际的应用中各有优劣,我们今天先来讲解第一种方法,第二种方法博主稍后再和大家分享。首先来说说第一种方法的原理,我们首先用Eclipse编写一个Java的库文件(.Jar),在这个库文件中我们会封装一系列的方法来为Unity提供接口,我们将这个库文件导出后可以将其放置到一个特定的目录下(Plugins/Android),然后我们就可以利用Unity提供的API来调用这些方法。好了,下面我们来看具体的过程吧,首先我们创建一个Android项目,并将其设为一个库,这里将其包名设为com.android.android2unity,这个包名很重要,我们在Unity中将用到这个包名。我们接下来在MainActivity.java这个类中编写代码,它将作为我们封装Android API的一个类。在编写代码之前,让我们来做这样一件事情,将位于D:\Program Files\Unity\Editor\Data\PlaybackEngines\androidplayer\release\bin\classes.jar(不同的计算机上,这个位置可能会有所不同,大家按照自己的路径添加即可)这个库加入到我们的项目中来,如图:


这个库是Unity为Android提供的一个库,主要提供了支持该平台的Player,具体的大家可以自己去查看它的类空间。好了,我们下面编写这样一个脚本:

package com.android.android2unity;

import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Vibrator;
import android.widget.Toast;


/* 引入Unity的包  */
import com.unity3d.player.UnityPlayerActivity;
import com.unity3d.player.UnityPlayer;

/* 如果需要Activity与Unity对接,可以通过继承UnityPlayerActivity来实现  */
/* 我们需要重写Activity的相关方法,在此节代码中,我们只需要调用Android API  */
public class MainActivity extends UnityPlayerActivity {

	//当前上下文
	private Context mContext=null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//初始化上下文
        mContext=this;
	}
    
	/* 定义一个调用Unity方法的方法 ,基于UnitySendMessage实现 。由于当前Activity没有采用   */
	/* Android的布局文件,所以我们无法使用Android的事件来完成这个方法的调用,我们  */
	/* 采用Unity调用的方法,虽然这样显得舍近求远,可是我们知道了如何在Android中调用   */
	/* Unity中定义的方法   */
	public void InvokeUnity(String mStr)
	{
	   UnityPlayer.UnitySendMessage("Vabille","SetCameraColor", "");
	}
	
	/* 定义一个打开Activity的方法,我们将在Unity中调用此方法 */
	public void StartWebView(String mUrl)
	{
		//创建一个Intent以打开一个新的Activity
	    Intent intent=new Intent(mContext,WebActivity.class);
	    //传入一个URL
		intent.putExtra("URL", mUrl);
		//打开Activity
	    this.startActivity(intent);	
	}

	/* 定义一个显示对话框的方法,我们将在Unity中调用此方法 */
	public void ShowDialog(final String mTitle,final String mContent)
	{
		/* 在UI线程下执行相关方法 */
		runOnUiThread(new Runnable()
		{
			@Override
			public void run() 
			{
				//创建Builder
				AlertDialog.Builder mBuilder=new AlertDialog.Builder(MainActivity.this);
				//创建对话框
				mBuilder.setTitle(mTitle)
				        .setMessage(mContent)
				        .setPositiveButton("确定", null);
				//显示对话框
				mBuilder.show();
			}
		});
	}
	
	/* 定义一个使设备震动的方法,我们将在Unity中调用此方法 */
	public void SetVibrator(long mTime)
	{
        Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
	    mVibrator.vibrate(mTime);
	}
	
	/* 定义一个使设备震动的方法,我们将在Unity中调用此方法 */
	public void ShowToast(String mContent)
	{
		Toast.makeText(mContext,mContent,Toast.LENGTH_LONG);
	}
}
     在这段代码中我们让MainActivity类继承自Unity提供的UnityPlayerActivity,这样我们就可以在Android中使用Unity提供的某些方法。在这段代码中我们定义了5个方法,即用于显示对话框的ShowDialog()方法、用于显示Toast的ShowToast()方法、用于打开一个Activity的StartWebView()方法、用于使设备震动的方法SetVibrator()方法以及用于调用Unity中定义的方法的InvokeUnity()方法,其中ShowDialog()方法需要在UI线程下运行。在这里,我们不需要为当前的Activity设置一个布局文件,所以我们没有使用setContentView()方法。

      接下来我们创建一个继承自Activity的类WebActivity,我们希望在这个页面中加载一个网页,网页的地址可以通过Unity来指定,我们首先来看布局文件avtivity_web.xml,它是一个简单的线性布局,在它的内部只有一个用于显示网页的WebView组件webView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
      相应地,它对应于WebActivity类,我们在MainActivity类中定义的StartWebView()方法即指向这个Acitivity:

package com.android.android2unity;


import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;


public class WebActivity extends Activity
{
	//网页组组件
	private WebView mWebView;
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//设置当前布局
        setContentView(R.layout.activity_web);
        //获取WebView
        mWebView=(WebView)findViewById(R.id.webView);
        //获取URL
        String mUrl=this.getIntent().getStringExtra("URL");
        //加载网页
        mWebView.loadUrl(mUrl);
	}
}
它的意义很明确,从MainActivity中读取传来的字符型参数URL,这是一个网页地址,我们通过这个地址打开一个网页。最后,我们来看项目的配置文件AndroidManifest.xml文件,这是一个比较重要的文件,我们在这里要做的事情是注册WebActivity、给应用分配相应的权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.android2unity"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="14" />
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.android.android2unity.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".WebActivity"/>
    </application>

    
</manifest>
        好了,到现在为止,我们基本上完成了Android插件的编写,最后我们要做的就是将它输出为一个Jar库,以便我们在Unity中使用,在这里要注意的是,所有的Java类、Android生成的配置文件类(如属性、布局、值等)都要编译,博主之前就是因为没有搞懂Jar库的编译,结果在Java、Unity两边费了不少的周折、来回奔波。如果对Java熟悉的朋友,一定会采用命令来输出库文件吧,不过博主是个菜鸟,对Java命令不太熟悉,所以博主采用的方法是通过文件->导出来导出Jar文件的,如图,我们需要选中src目录和R.java文件,如果有第三方的库的话还需要选中libs文件夹:


这样我们就可以直接输出我们需要的Jar库文件了。这样我们就完成了在Android中编写Unity插件的任务,接下来,我们进入Unity的势力范围吧,哈哈!


        在Unity这块呢,我们继续用我们前一篇文章中的项目,我们继续使用FF中这个漂亮的妹子(原谅我不知道她叫什么名字)如图:


      下面请大家按照这样的结构来组织Android插件的目录:

       ----------Assets

                 ----Plugins

                     -----Android

                         -----bin(存放导出的Jar)

                         -----libs(存放第三方的库)

                         -----res(资源文件夹,可直接复制Android项目)

                         -----AndroidManifest.xml(配置文件,可直接复制Android项目)


      最终的效果应该是这样:


     

     好了,下面我们来编写C#脚本AndroidAPI.cs

using UnityEngine;
using System.Collections;

public class AndroidAPI : MonoBehaviour {

	void Start()
	{
		//设置当前游戏体的名字,在Android中我们将使用这个名字
		this.name="Vabille";
	}

	//定义一个方法以改变摄像机背景颜色,我们将在Android中调用这个方法
	void SetCameraColor()
	{
		//设置摄像机背景颜色
		Camera.main.backgroundColor=new Color(1.0F,0.5F,0.5F);
	}

	void OnGUI () 
	{
		//通过API调用对话框
	    if(GUILayout.Button("调用Android API显示对话框",GUILayout.Height(45)))
		{
			//获取Android的Java接口
			AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer");
			AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity");
			//构造参数
			string[] mObject=new string[2];
			mObject[0]="Unity3D";
			mObject[1]="Unity3D成功调用Android API";
			//调用方法
			jo.Call("ShowDialog",mObject);
		}

		//通过传值打开Activity
		if(GUILayout.Button("调用Android API中打开Activity",GUILayout.Height(45)))
		{
			//获取Android的Java接口
			AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer");
			AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity");
			//打开博主的博客
			jo.Call("StartWebView","http://blog.csdn.net/qinyuanpei");
		}

		//通过API调用Toast
		if(GUILayout.Button("调用Android API中的Toast",GUILayout.Height(45)))
		{
			//获取Android的Java接口
			AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer");
			AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity");
			//打开博主的博客
			jo.Call("ShowToast","为Unity3D编写Android插件是件苦差事!");
		}

		//通过API调用Toast
		if(GUILayout.Button("调用Android API中的震动方法",GUILayout.Height(45)))
		{
			//获取Android的Java接口
			AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer");
			AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity");
			//打开博主的博客
			jo.Call("SetVibrator",40);
		}

		//通过API调用Toast
		if(GUILayout.Button("通过SendMessage调用Unity中的方法",GUILayout.Height(45)))
		{
			//获取Android的Java接口
			AndroidJavaClass jc=new AndroidJavaClass("com.unity3d.player.UnityPlayer");
			AndroidJavaObject jo=jc.GetStatic<AndroidJavaObject>("currentActivity");
			//打开博主的博客
			jo.Call("InvokeUnity","");
		}

	}
}
     这里的方法都是调用在Android中定义好的方法,主要是利用AndroidJavaObject的Call()方法,该方法有两个参数,第一个参数是一个字符型的变量,是我们要调用的方法的名字,第二个参数是一个object[]类型,是我们要调用的方法的参数。好了,我们一起来看看手机上运行的效果吧!




       这就是今天的成果了,不过大家都知道我的习惯,每次我在文章中解决不了的问题都会在博客里说出来让大家帮我解决,而今天的问题就是ShowToast()方法和SetVibrator()方法一直没有被调用,博主怀疑是不是Unity提供的Java接口能力有限,只能访问Android的某些接口,不知道大家是怎么看的,如果大家知道的话,希望大家可以告诉我啊,呵呵。

       最后,想说的一点就是我们在C#里定义了一个SetCameraColor()的方法,这是一个改变摄像机背景的方法,我们在Android中使用InvokeUnity()方法来访问这个方法,由于在第一个页面中,我们没有使用Android的布局元素,因此Android的事件我们无法使用,我们依然采用在Unity中调用的方法,最然这样显得舍近求远,但是这说明了一个问题,Android可以调用Unity的的方法,而具体实现就是通过SendMessage()来实现的,博主个人觉得这是一种委托吧。大家注意到最后屏幕的颜色变成了红色,说明这个方法被调用了。好了,今天的内容就是这样啦,写完这篇文章博主感觉好累啊!


每日箴言:孤独是人生的伴侣,寂寞是人生的常客。人生就是一场修行,修行要有耐性,要能忍受孤独、无悔寂寞。



      

     喜欢我的博客请记住我的名字:秦元培,我博客地址是blog.csdn.net/qinyuanpei。
     转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/39348677


         本文源代码下载 :Unity项目  Android项目


Unity3D触摸操作

阅读数 587

记录Unity3D学习过程!

博文 来自: duanke111
没有更多推荐了,返回首页