Unity编程技巧:使用宏定义,让代码更整洁,实现代码和渠道SDK解耦等

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u013746357/article/details/78903693

笔者从一年前开始做VR开发,移动端PC端的应用都有,因为当前VR市场还很混乱,并且硬件标准太多单我使用过作开发的VR设备就有5、6种之多,更别说只是用过听过的设备,并且每一家的API都不一样,这也增加了发不同的渠道包的工作量。这里我将就我使用的只用解决方案,做一下简单的描述,因为还在公司任职不便使用项目代码,所以主要就是使用方法,没有太多的具体代码

哪里设置全局宏,打开BuildSetting,在下图红线处设置输入宏,不同宏用分号隔开

这里写图片描述

问题1:不同硬件厂商的SDK代码互相冲突

国内做VR硬件的厂商很多,而他们家的SDK代码大部分都一样(具体就是都和oculus SDK的代码一样,具体为什么一样我也就不明说了),关键是一些家的SDK和别人一样就一样吧,你加一个自己家的namespace 把代码区分开好不好,他们偏不,也是任性的不行。这就苦了我们做应用开发的,拿到一个B家的SDK导入到现成(做过A家的硬件适配)的项目下,全是报错,一个一个查,发现是代码冲突,但是又必须适配这家的设备,怎么办,把A家的SDK删掉?当然这是一种解决办法,但是项目中做过A家的适配,删掉了A家的SDK,引用到SDK的代码妥妥的报错啊!!况且以后还要给A家的硬件打包程序。

怎么办?使用全局宏定义
在Unity BuildSetting 下设置两个全局宏 VRA;VRB
然后把A家的SDK代码全部用VRA的宏设置下:
    SDKA.cs
    #if VRA
    ......
    #endif
把B家的SDK代码全部用VRB的宏设置一下:
    SDKB.cs
    #if VRB
    .......
    #endif

问题2:不同VR设备的SDK里某一个同样功能的API接口不一样

假设我们结果了SDK冲突的问题,然后就是实际应用了,比如A家SDK获取手柄输入的方法是InputA.GetKey();B家SDK的获取手柄输入的方法是InputB.GetKey();
我们不想每次打包都修改代码,尤其是发包比较频繁的情况下,而且这样也不方便做代码管理,哪天不小心写错了,等到打包出来又没有测试,就完蛋了。同时,如果哪天不用做B家的SDK了,需要从项目下把B的SDK删掉,那还要把引用到B家SDK的代码一个个修改一遍。怎么办?使用全局宏定义+代码功能抽象
定义一个获取输入的类CustomInput.cs。项目中所有获取玩家输入的地方都要使用这个类。该类的内容如下:

//这里只是个简单的结构示例,具体的代码根据不同VR设备的输入功能 要更加复杂,而且代码不是在编辑器里写的,如有语法错误还请见谅
//CustomInput.cs
//这个类应该使用单例模式,但不是我们讨论的重点,这里没有写
public class CustomInput:MonoBehaviour {
    public static System.Action OnClick;//点击手柄或者头盔上的触摸板
    private void Update()
    {
        #if SDKA
         CheckSDKAInput();
        #elif SDKB
         CheckSDKBInput();
        #endif
    }
    #if SDKA
    private void CheckSDKAInput()
    {
        if(InputA.GetKey())
        {
            if(OnClick!=null)On_Click();
        }
    }
    #endif
    #if SDKB
    private void CheckSDKBInput()
    {
        if(InputB.GetKey())
        {
            if(OnClick!=null)On_Click();
        }
    }
    #endif
}
//使用输入的地方
//Move.cs
public class Move:MonoBehaviour
{
    private void OnEnable(){
        CustomInput.OnClick+=OnClick;
    }
    private void OnDisable(){
        CustomInput.OnClick-=OnClick;
    }
    private void OnClick()
    {
        //跳跃移动或其他逻辑
    }
}

这样我们的具体逻辑代码就和不同平台的SDK完全解耦,如果某家SDK代码有改动,完全不会对项目其他部分的代码有任何影响,只需要修改CustomInput.cs这里一处的代码就可以。

问题3:每一家代表玩家对象的预制体都不一样。

做过VR开发的一定知道,因为VR模式是双摄像机代表左右眼,而且往往还有代表左右手的3Dof手柄或者6Dof手柄。为了降低开发者的上手难度,SDK里都会提供一个预制体,把这个预制体放到场景里就是玩家对象。例如HTCCameraRig代表HTC vive PC端VR的玩家对象,GearCameraRig:代表GearVR 的玩家对象IVRCameraRig代表Idealens移动端VR的玩家对象。我们不能每次打不同厂家的包时都拖拽一个Prefab到场景里吧,况且为了实现一些逻辑这些预制体上我们会挂载一些自己的脚本刚体碰撞之类的,而且场景内其他地方的代码可能对这个预制体有引用关系,手动切换并不是一个合适的方法,因为是人就会有失误。怎么办?还是用全局宏
把需要用到的所有平台的预制体都拖拽到场景的一个代表玩家的gameobject下
这里写图片描述

//VRSwitchCameraRig.cs
//把该脚本挂到Player对象上,并且把对应的transform拖拽到固定的内容上。
//HTC vive
public class HTCCameraRig
{
    public Transform parentObj;
    public Transform head;
    public Transform leftHand;
    public Transform RightHand;
}
//Gear VR 
public class GearVRCameraRig{
    public Transfrom parentObj;
    public Transfrom head;
}
//Pico 设备
public class PVRCameraRig{
    public Transform parentObj;
    public Transform head;
    public Transform hand; 
}
//如果有其他设备,继续定义其他设备的与预制体结构
public class VRSwitchCameraRig : MonoBehaviour{
    public HTCCameraRig htcCameraRig;
    public GearVRCameraRig gearVRCameraRig;
    public  PVRCameraRig pVRCameraRig;
    public Transfrom mHead{ //项目下其他代码如果需要获取头部信息,都从这里拿,左右手或者其他部件同样如此,这里不再写
        get{
            #if HTCVIVE
            return htcCameraRig.head;
            #elif GEARVR
            return gearVRCameraRig.head;
            #elif PICOVR
            return pVRCameraRig.head;
            #endif
        }
    }
    void Awake()
    {
        #if !HTCVIVE
        Destroy(htcCameraRig.parentObj.gameObject);
        #endif

        #if !GEARVR
        Destroy(gearVRCameraRig.parentObj.gameObject);
        #endif

        #if !PICOVR
        Destroy(pVRCameraRig);
        #endif
    }
}

猜你喜欢

转载自blog.csdn.net/u013746357/article/details/78903693
今日推荐