众所周知, Unity中没有提供UI解决方案, 只能靠第三方的插件来完成. 比较著名的有NGUI等, 但是这种方案不仅需要额外付费(虽然不多), 并且类似NGUI的插件还不那么易用, 使用起来过于复杂.

这里我尝试使用iPhone的原生UI(Cocoa Touch)来作为Unity的UI. 这个听起来似乎很容易的事情, 其实却比我想象的要难的多的多. 主要原因就在于Unity根本就不是想让你这么用的, 3D引擎为了效率, 一般都需要比较专横的占用系统资源, 在本来速度有限的移动平台就更加需要这样了, 这样才能发挥出硬件的极限水平, 制作出更精良的游戏. 鉴于这个原因, 这种方法并不适于性能要求高的游戏.

用原生UI的优点

易用: 原生UI的使用简单, 可用的第三方界面库也很丰富, 特别是对于已经有很多iOS app开发经验的人来说.

App风格: 风格上可以很贴近原生app, 假如真有这样的需求, 那么这个优势是无限大的, 要在Unity去模拟iOS Native UI是个能让开发者自杀的需求. 要是模拟的不到位, 更加会不伦不类.

免费: 因为NGUI等第三方的UI插件比起Unity本身来说并不贵, 所以这也不算多大的好处.

用原生UI的缺点

自定义功能弱: 要是需要一个很牛, 很炫的UI, 特别是想要3D效果的UI, 自定义起来, 还是类似NGUI的UI插件要更加强大和方便.

效率更低: 比起在Unity中直接绘制UI, 用原生UI效率要更低, 这个很好理解, 因为在Unity中绘制UI时, Unity可以尽可能的优化, 用尽量少的draw call去绘制UI, 而Native UI并不受控制.

不跨平台: 假如你用了iOS的原生UI, 那么你就无法简单的把游戏移植到其他平台了, 起码UI部分你得完全重做.

开发麻烦: 作为不能跨平台的衍生问题, 本来Unity的游戏你可以完全在PC/Mac上开发和运行, 然后最后在iPhone/Android上发布, 而一旦用了原生的UI, 几乎是必然的, 你运行时一定需要在设备上才能运行. 这不仅是原生UI的限制, Unity的对iOS的插件机制也有这样的要求. 另外, 大家都知道, 一旦牵涉到跨语言的开发, 调试起来就会很麻烦, 用原生UI也不例外, 这算是另外一个增加了开发难度的事情.

最后一个问题, 而且是最重要的问题是, 从Unity生成一个XCode工程, 然后到XCode编译完成, 再到载入真机的过程是相当~相当~相当~相当~相当的漫长, 真的很长, Unity的技术团队简直是担心C#的开发着享受不到C++开发者的福利啊~~~~呵呵, C++开发者, 你懂的.

但是, 在这种情况下, 开发效率会受到相当~相当~相当~相当~相当大的影响, 相信我, 买个好机器吧… 或者, 哭去吧…

开发环境

以下所有代码仅在Mac OS X 10.8.2, Unity 4.0.0f7, XCode 4.5.2(4G2008a) 环境下测试, 其他环境不保证可用.

基础: Unity 插件编写(managed-to-unmanaged)

这是在Unity中使用Objective-C的唯一方法. 所以这是使用原生UI的基础, 首先简述一下.

步骤:

1.在Unity的脚本中使用 [DllImport ("__Internal")] 特性(attribute)来标识用Objective-C/C++实现的函数. 如下:

[DllImport ("__Internal")]

private static extern float FooPluginFunction ();

2.其次, 在Objective-C/C++中用extern "C"标识接口:

// .mm

extern "C" {

float FooPluginFunction () {

return 10.1f;

}

}

3.全部的C#文件实现为一个组件(即继承于MonoBehavior如下:

using UnityEngine;

using System.Runtime.InteropServices;

public class NativeBinding : MonoBehaviour {

// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

}

[DllImport ("__Internal")]

private static extern float FooPluginFunction();

void Awake() {

print (FooPluginFunction());

}

}

注意using System.Runtime.InteropServices;必不可少.

然后, 当然将这个组件绑定到某个对象上也是必不可少, 不然Awake永远不会运行.

4.在最新版的Unity中, 多了个很方便的特性. 当把原生代码放在Assets/Plugins/iOS中时(不允许再有子目录了), 在生成XCode工程的后, 代码都会放在Libraries中, 解决了以前生成工程后还需要自己添加代码的问题.

编译运行后可以看到会输出10.1(一定能够要真机运行).

原生代码调用Unity的Script代码(native-to-managed)

通过UnitySendMessage函数, 有个问题是似乎没法获得返回值. 还是接上个例子, 通过反过来调用的方式, 输出10.1后再输出一个10.2.

// .mm

extern "C" {

float FooPluginFunction () {

UnitySendMessage("Main Camera", "Print", "10.2");

return 10.1f;

}

}

上述代码就能直接调用Main Camera的Print函数.

void Print(string message) {

print (message);

}

需要注意的是, 上述调用并不是同步的,, 所以能看到, 虽然上述代码是先调用的UnitySendMessage函数, 但是实际上, 10.2字符串输出的会晚于10.1, 官方文档说UnitySendMessage会在下一帧被调用.

可以看到这个接口带来的问题不仅不能返回值, 同时传递的参数还只能是字符串.

UnitySendMessage的一个研究

我看的这个接口的第一反应是, 这个UnitySendMessage在Unity中用的是SendMessage实现的, 因为一个Unity对象绑定的组件可能有多个, 也可能有多个同样命名的函数, 此时会同时调用所有符合条件的函数, 这体现了Unity整体设计的动态性. 事实检验, 果真如此.

显示原生UI的尝试(Try to use Native UI in Unity)

这是本文真正想做的事情. 在互联网上搜了一圈, 问这个问题的多, 但是知道回答的太少. 我想可能需要我写完本文后给他们一一回答… 是不是有些托大啊-_-!

UI显示

首先, 讲前面的知识用上, 并且取个厚道的名字:

// .h

#import

// .mm

#import "NativeBinding.h"

extern "C" {

void _ActivateUI() {

}

void _DeactivateUI() {

}

}

然后, 添加一个我们用于显示UI的类. 我这里直接用XCode生成了. 其他代码都不变, 增加一个单件的接口和实现. 代码就很简单了.

// .h

#import

@interface RootViewController : UIViewController

+ (id) sharedManager;

@end

// .mm

#import "RootViewController.h"

static RootViewController *sharedRootViewController = nil;

@interface RootViewController ()

@end

@implementation RootViewController

+ (id) sharedManager {

if (!sharedRootViewController) {

sharedRootViewController = [[self alloc] initWithNibName:nil bundle:nil];

}

return sharedRootViewController;

}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

// Custom initialization

}

return self;

}

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.

}

- (void)didReceiveMemoryWarning

{

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

@end

然后把RootViewController的显示代码加入到Script调用中去, 怎么加呢? 最关键的代码是在:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];

不需要琢磨OpenGL的那个View怎么改了, 取得keyWindow就行了. 然后就是addSubView的事情而已了.

完整的代码如下:

// .mm

#import "NativeBinding.h"

#import "RootViewController.h"

extern "C" {

void _ActivateUI() {

//Get the applications UIWindow

UIWindow *window = [[UIApplication sharedApplication] keyWindow];

NSLog(@"window = %@", window);

//Create the RootViewController from a XIB file.

RootViewController *rootViewController = [RootViewController sharedManager];

//Add the RootViewController view to the main window.

[window addSubview: rootViewController.view];

}

void _DeactivateUI() {

if ([RootViewController sharedManager] != nil) {

// Code ~~

}

}

}

此时只要在Unity中直接调用_ActiveUI就OK了.

using UnityEngine;

using System.Runtime.InteropServices;

public class NativeBinding : MonoBehaviour {

void Start () {

ActivateUI();

}

[DllImport ("__Internal")]

private static extern void _ActivateUI();

public static void ActivateUI() {

print ("ActivateUI");

if (Application.platform == RuntimePlatform.IPhonePlayer) {

_ActivateUI();

}

}

[DllImport ("__Internal")]

private static extern void _DeactivateUI();

public static void DeactivateUI() {

print ("ActivateUI");

if (Application.platform == RuntimePlatform.IPhonePlayer) {

_DeactivateUI();

}

}

}

这里比前面的代码稍微正式一点, 判断了一下平台, 其他的内容其实已经讲过了. 此时运行程序(还是在真机啊~~~), 然后就能看到一个白屏了. 为了稍微有些内容, 在Interface builder中随意添加控件吧. 一顿乱摆之后:

UI + Unity

这个是第二个难点了, 目前的实现方式有个很大很大的问题, Unity的View全都挡住了, Development编译时右下角那行字都没有了. 这个根本没法用嘛.

刚开始我还考虑是不是通过分离控件, 即通过将控件的尺寸调整到合适大小, 合适位置, 直接加到keyWindow上去, 后来发现其实没有这个必要, 直接把View的background调整为透明即可… 这个真是比我想象的要简单太多…

另外, 假如还想更像app呢, 可以在工程配置里面把status bar弄出来.(在Unity生成的工程中, status bar默认隐藏了.)

下面是显示效果, 为了展示Unity的场景, 我按照惯例显示了一个3D的Hello World, 并且给了一个打了动态光源的球. enjoy it!

总结

其实到此为止, 想要实现的功能基本都能实现了, 剩下的也就是一些细节了. 但是, Unity的开发团队都不太推荐这种方式, 同样的, 我也不推荐大家使用… 使用后才能知道到底有多痛苦, 特别是非常非常非常非常漫长的编译过程…

最后编辑:2015-01-12作者:wy182000

这个作者貌似有点懒,什么都没有留下。

unity 3d iphone android 通用,在Unity3D中使用iPhone原生UI相关推荐

  1. unity 不再渲染局部_在Unity3D中的渲染优化-减少需要处理的顶点数目

    1.优化几何体 3D游戏制作通常都是由模型制作开始的.我们应该尽可能减少模型中三角面片的数目,一些对于模型没有影响,或者是肉眼很难察觉到区别的顶点都要尽可能去掉.为了尽可能减少模型中的顶点数目,美工人 ...

  2. 【Unity Shaders】Reflecting Your World —— Unity3D中简单的Cubemap反射

    在Project中可以创建我们自己的Cubemaps,现在,我们可以来看一下如何使用这种新的贴图类型来在Shaders中模拟反射效果.使用Cubemaps进行反射的原理实际上非常简单,但是这将给你的S ...

  3. 【Unity Shaders】Reflecting Your World —— Unity3D中的法线贴图和反射

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  4. Unity 3D下开发2D飞行游戏中的背景滚动

    背景滚动 有以下几点必要的: 在Canvas下创建Raw Image组件 背景图片设置为Texture 填充方式为Repeat重复填充方式 C#代码 using UnityEngine; using ...

  5. Unity 3D + Vuforia制作AR人物互动

    原文地址:http://blog.csdn.net/ekhsofxe_ibb/article/details/18655905 话说之前说过了咱与本地漫展商合作推出AR app,虽然他们之前也已经做过 ...

  6. Unity 3D游戏编程自学#3——Unity 3D初步

    1.开始 在创建的项目文件夹中,各个子文件夹的作用: Assets:保存游戏所需资源. Library:保存当前项目运行所需要的库. ProjectSettings:保存项目设置信息. Temp:保存 ...

  7. Unity 3D 碰撞体(Collider)|| Unity 3D 触发器(Trigger)

    在游戏制作过程中,游戏对象要根据游戏的需要进行物理属性的交互. 因此,Unity 3D 的物理组件为游戏开发者提供了碰撞体组件.碰撞体是物理组件的一类,它与刚体一起促使碰撞发生. 碰撞体是简单形状,如 ...

  8. Unity 3D Canvas画布

    Unity 3D Canvas画布 Canvas 是画布,是摆放所有 UI 元素的区域,在场景中创建的所有控件都会自动变为 Canvas 游戏对象的子对象,若场景中没有画布,在创建控件时会自动创建画布 ...

  9. Unity 3D:在现有的Android游戏场景中显示AdMob的横幅

    2019独角兽企业重金招聘Python工程师标准>>> 关于如何在现有的Android项目现场显示AdMob的横幅,在一个Android项目中使用一个简单的Android JAR文件 ...

最新文章

  1. python元类 orm_python-进阶-元类在ORM上的应用详解
  2. 上周回顾:***猖狂叫板欧美政府 赛门铁克赔偿羞羞答答
  3. Android分享功能,微博、QQ、QQ空间等社交平台分享之入门与进阶
  4. evernote100个做笔记的好方法
  5. 从留存的本质出发,制定留存策略
  6. 结合中国古典文化取名 华为意在把传说化为现实奇迹
  7. asp.net应用程序无法连接oracle数据库,2020:ASP连接Oracle数据库问题的解决过程
  8. Android 的安全性岌岌可危!
  9. 谷歌TPU2代有望取代英伟达GPU?测评结果显示…
  10. Activity与Service之间交互并播放歌曲
  11. 数理化计算机电子 武大水平,全方位比较南开大学、武汉大学——以数据为基础.doc...
  12. linux python3命令_linux安装python3
  13. 先锋网络电视 v3.36.4 钻石版 怎么用
  14. iOS面试题系列之常见算法
  15. HCIA 学习笔记 准备考试
  16. 谷歌chrome浏览器被hao123 360等劫持问题解决方案
  17. 【SequoiaDB 学习笔记】巨杉分布式数据库初接触
  18. 17互联网产品的交互设计(文智老师公开课笔记)
  19. java来源_java的来源
  20. 计算机一级考试:选择题汇总D(精简版)

热门文章

  1. [编程范式]以炒菜为例,讲解各种编程范式
  2. 炒菜更香的39个小窍门
  3. LCD1602液晶显示模块
  4. 大话设计模式(五)观察者模式
  5. python爬取天眼查数据(未破解图片验证及ajax版)
  6. 2021-08-11
  7. 我国有较大的AI大模型应用市场,在应用领域具有优势
  8. python斗地主出牌算法_斗地主之用蚁群算法整理牌型:如何进行牌力估计
  9. java制作摄影建模,照片建模的拍摄要求
  10. 简单定制统信UOS镜像的方法