Unity3d开发之实现在Unity3d层C#脚本和在Xcode层Objective-c语言的通信以及NGUI的屏幕适配问题

来源:互联网 发布:小蜜软件怎么样 编辑:程序博客网 时间:2024/05/21 11:28

       几日前,笔者碰到一个NGUI的屏幕尺寸的适配问题。情况是这样子的:Unity3d编译了一个iPhone版的Xcode工程,非Universal版,进入真机测试的时候,发现当该iPhone版的工程在iPad2真机上NGUI出现了问题,如下图:


 

     

        由图片可分析出,NGUI的位置都是正确的,但是大小不正确;显然这是由于屏幕分辨率导致的问题,因为NGUI用的是高清图,并且iPad屏幕是非retina屏幕,NGUI的底层代码根据这个屏幕分辨率来缩放,如果屏幕是全屏的,基本上没啥问题;进一步可以锁定问题出在编译的Iphone版工程运行在iPad上面,由于Unity3d的摄像头视野大小是iPhone的屏幕大小,但是实际的屏幕分辨率却是非retina,而图片却是retina导致在非retina屏幕上显示出了retina图片的真实像素尺寸(本来应该缩小一倍)。找到问题的原因后,就可以着手解决了。

        由于查看Unity3d的Screen这个类提供的API没有查询屏幕的分辨率是否是retina屏幕的,只能通过Objective-c的API查询。在这里,笔者的思路是,通过在Unity3d层的NGUI的底层NGRoot.cs(NGUI负责屏幕分辨率适配的类)这个类的C#脚本中向Xcode层的Objective-c语言发送消息查询当前的屏幕是非retina屏,是否iPad硬件,再加上一个根据当前Xcode的版本的开关变量(比如是iPhone版就打开,如果是iPad版或者Universal版就关闭)一起判断,决定是否要将当前屏幕的分辨率乘以2(NGUI底层是用某个常量除以当前屏幕的分辨率来适配屏幕的)再来计算缩放。这涉及到Uinty3d层与Xcode层的通信问题。

       幸好,C#给我们提供了多平台适应的API,使用System.Runtime.InteropServices,可以定义一个接口,在c#项目外实现。这里可以在C#脚本里定义在需要在Xcode里实现的接口,在接口前加上[DllImport("__Internal")]即可。代码实例如下:

在Unity3d层的代码:

//----------------------------------------------//            NGUI: Next-Gen UI kit// Copyright © 2011-2012 Tasharen Entertainment//----------------------------------------------using UnityEngine;using System.Runtime.InteropServices;/// <summary>/// This is a script used to keep the game object scaled to 2/(Screen.height)./// If you use it, be sure to NOT use UIOrthoCamera at the same time./// </summary>[ExecuteInEditMode][AddComponentMenu("NGUI/UI/Root")]public class UIRoot : MonoBehaviour{public bool automatic = true;public int manualHeight = 800;[DllImport ("__Internal")]public static extern bool isDoubleScreen ();bool isIPhonePlatform = false;Transform mTrans;void Start (){mTrans = transform;UIOrthoCamera oc = GetComponentInChildren<UIOrthoCamera> ();if (oc != null) {Debug.LogWarning ("UIRoot should not be active at the same time as UIOrthoCamera. Disabling UIOrthoCamera.", oc);Camera cam = oc.gameObject.GetComponent<Camera> ();oc.enabled = false;if (cam != null)cam.orthographicSize = 1f;}if (Application.platform == RuntimePlatform.IPhonePlayer) {isIPhonePlatform = true;}                        }void Update (){manualHeight = Mathf.Max (2, automatic ? Screen.height : manualHeight);if (isIPhonePlatform) {if (UIRoot.isDoubleScreen()) {manualHeight *= 2;}}float size = 2f / manualHeight;Vector3 ls = mTrans.localScale;if (!Mathf.Approximately (ls.x, size) ||!Mathf.Approximately (ls.y, size) ||!Mathf.Approximately (ls.z, size)) {mTrans.localScale = new Vector3 (size, size, size);}}}

在Xcode层的代码:


#pragma mark - logic#define isRetina ([UIScreen mainScreen].currentMode.size.width / [UIScreen mainScreen].bounds.size.width == 2 ? YES : NO)//定义高清图片的开关 ,1打开,0关闭#define isRetinaPicture 1//是否是iPhone程序运行在iPad上#define isPhoneAppOnPad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && [[[UIDevice currentDevice] model] hasPrefix:@"iPad"])bool isDoubleScreen () {    if (!isRetina && isPhoneAppOnPad && isRetinaPicture) {        return true;    }    return false;}


  解决后的NGUI在iPad屏幕上的显示如下图:


  


    好了,上边介绍了如何在Unity3d层向Xcode层发送查询消息解决了NGUI屏幕分辨率适配的问题。接下来再介绍如何在Xcode层向Unity3d层发送消息,在这里,Unity3d提供了一个API来实现,即

void UnitySendMessage(const char* obj, const char* method, const char* msg);

         这个API有三个参数,第一个参数是Unity3d里接收消息的物体的名称,第二个参数是Unity3d绑定的物体的脚本里实现的方法名称,第三个参数是是第二个参数的实现方法里需要接收传递的数据参数。代码实例如下:

   Xcode层的代码:

NSString *param = @"param";UnitySendMessage("XcodeAdapter", "methodFromXcode", [param cStringUsingEncoding:NSUTF8StringEncoding]);


Unity3d层的代码:

using UnityEngine;using System.Collections;using System.Runtime.InteropServices; //该脚本绑定在Unity3d场景里一个叫XcodeAdapter的GameObject上public class XcodeAdapter : MonoBehaviour {public void methodFromXcode (string param){Debug.Log(param + "~~~~!!!!");}}


         本文结束~~~~