3DTouch在Unity游戏开发中的一个坑

起因

 游戏测试过程中有这样一个反馈, 按住控制角色行走, 当按住触摸屏幕左铡边缘部位时, 有时会有1秒左右的延迟. 很是影响游戏的体验.
多次测试后, 具体表现为

表现

1. 支持3DTouch的设备才有这个问题, iphone6s/iphone7, 其它设备没有这个问题
2. 这些设备关闭3DTouch功能后, 问题就消失了

原因

所以问题就在于3DTouch上了. 15年10月, 苹果推出这项技术后, 其中一个使用小技巧就是
在竖屏模式下. 任意界面在屏幕左侧边缘处使用3D Touch轻按后再次重按或向右滑动至屏幕中部即可激活多任务界面。
正是这个系统级的判定, 导致了这一游戏或应用中的问题.

解决

寄希望于用户去手动关闭这个功能, 不能算是个解决方式
好的方式是: 取到窗口对象的UIGestureRecognizer, 设置它的delaysTouchesBegan为false

在Unity下具体操作方式为

在 Unity 插件目录下创建以下文件:

/path/to/unity/project/Assets/Plugins/iOS/MyAppController.h

/path/to/unity/project/Assets/Plugins/iOS/MyAppController.mm

注意,文件名必须是 ___AppController,前缀可自选,但不能省略;否则在 Build 项目的时候,会被移动到错误的目录中去。

MyAppController.h文件

#import "UnityAppController.h"


@interface MyAppController : UnityAppController
@end

IMPL_APP_CONTROLLER_SUBCLASS (MyAppController)
MyAppController.mm文件内容

#import "MyAppController.h"

@implementation MyAppController

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [super application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}

- (void) preStartUnity
{
    UIGestureRecognizer* gr0 = _window.gestureRecognizers[0];
    gr0.delaysTouchesBegan = false;
    
    UIGestureRecognizer* gr1 = _window.gestureRecognizers[1];
    if(gr1 != NULL){
        gr1.delaysTouchesBegan = false;
    }
}


@end

在 Build iOS Project 的时候,Unity 会自动把MyAppController 复制到 /path/to/project/Libraries/MyAppController

而原来的 UnityAppController.mm 则在 /path/to/project/Classes/UnityAppController.mm

那么 Unity 是如何知道要使用我们定制的 MyAppController 而不是使用默认的 UnityAppController 呢?

关键在于 IMPL_APP_CONTROLLER_SUBCLASS 这个宏

很多文章在提到继承 UnityAppController 后,需要找到 /path/to/project/Classes/main.mm里面的:

const char* AppControllerClassName = "UnityAppController";

将其修改为:

const char* AppControllerClassName = "MyAppController";

从而使 Unity 在启动的时候使用我们制定的MyAppController 类。

这样一来,每次 Build 项目都需要手动去修改这个常量,岂不是自找麻烦。其实完全可以利用 Objective-c 的特性来自动完成这个操作。

注意到 UnityAppController.h 里面有这样一个宏:

#define IMPL_APP_CONTROLLER_SUBCLASS(ClassName) \
@interface ClassName(OverrideAppDelegate)       \
{                                               \
}                                               \
+(void)load;                                    \
@end                                            \
@implementation ClassName(OverrideAppDelegate)  \
+(void)load                                     \
{                                               \
    extern const char* AppControllerClassName;  \
    AppControllerClassName = #ClassName;        \
}                                               \
@end

将这个宏加到 MyAppController.h 中,即可实现自动设置 AppControllerClassName :

IMPL_APP_CONTROLLER_SUBCLASS (MyAppController)

是不是很神奇呢!IMPL_APP_CONTROLLER_SUBCLASS 使用了两个 Objective-C 的特性,一是 category ,用来给已有的类扩展新的方法;二是 +(void)load 静态方法,它会在运行时 MyAppController 类被加载到内存中时触发,这个时间点比 int main() 函数还要早,所以能够提前“篡改” AppControllerClassName,达到我们的目的。


完毕!




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值