【Unity优化】优化Android平台拖动地图表现

一、Android平台上拖动不平滑的现象

团队使用的热更新框架还是比较老的ToLua,拖动地图的逻辑,实现的方案是,在地图上放置一个合适大小的Image组件作为Raycast Target的对象,统一接受和处理跟地图拖动相关的逻辑。

在C#层专门建立一个DragManager作为拖动事件管理器,其内部实现了IDragHandler,IPointerDownHandler,IPointerUpHandler,IScrollHandler等EventSystem事件接口。DragManager根据游戏交互的需求,实现了:单指拖动,双指拖动,短按,长按等接口。Lua层注册对应的函数,实现对应的响应时间事件。

单指拖动地图在Lua层的逻辑为,计算当前次的单指拖动事件在屏幕上的位置,以及上次事件在屏幕上的位置,计算屏幕上的拖动位移。由于我们游戏是2D游戏,使用的平视相机,因此可以简单的将屏幕上的位移通过相机参数简单映射为世界坐标系相机的移动距离,计算方式既可以使用相机的ScreenToWorldPoint接口,也可以通过orthographicSize和Screen.height的比例换算。

经过测试,这个方法在iOS平台没有问题,拖动起来非常的丝滑。但是在Android上,拖动起来,有抖动现象,显得游戏卡顿。

二、探究过程

这种卡顿,初步的设想有以下几种可能:

1、渲染层面的问题、掉帧等

由于我们游戏测试环境下一直有帧率显示,用高性能的安卓设备测,完全能跑满60fps,并没有掉帧现象,但是视觉效果上还是显得卡顿。此外,由于我们游戏会锁定帧率,并没有开启垂直同步VSync,经测试,也排除了这种原因。

2、事件接口的问题

除了IDragHandler以外,还尝试了自己在Update里使用Input.GetTouch的方式来替代OnDrag事件,但是经过测试,依然会卡顿。

3、生命周期函数选择问题

除了在Update里尝试GetTouch,还在FixedUpdate,LateUpdate里尝试了这样的方案,也依然是抖动的。

4、Lua的调用时机的问题

由于在Project Setting里的Script Execution Order中将LuaLooper的时机提前,有可能导致Lua的update和渲染不在同一帧。为此,选择了尝试移除Lua的控制逻辑,用最简单的C#脚本去实现。但是经过测试也依然存在抖动现象。

5、时间获取不对

由于计算用的是Time.deltaTime,有可能是这个时间和触摸事件发生的时间不一致,因此尝试在C#中,使用System.DateTime.Now去统计时长,并传递给Lua层使用。但是即便这么处理,也依然存在抖动的现象。

6、屏幕刷新率问题

由于测试设备有高刷,120帧,怀疑可能和刷新率有关。为此关闭手机的高刷测试,但是测试结果没有改善。

初步结论,最可能原因有

1、Unity3d游戏引擎给OnDrag接口或者GetTouch返回的位置值,在Android平台本身就是不及时的,不平滑的

2、获取事件时获取到position和事件发生的时机还是不对,但是由于Unity有自己的循环周期,无法准确获取事件触发真实时间。

二、插值函数

既然获取到数值不平滑,能够采取的一个常见策略就是进行插值。一般使用的差值方式有几种:

1、使用SmoothDamp函数

cs 复制代码
var smoothPos = Vector3.SmoothDamp(cPos, targetPos, ref currentVelocity, smoothTime);

2、使用Lerp函数并用一个固定的参数,比如10*dt

cs 复制代码
Vector3.Lerp(currentPos, targetPos, lerpFactor * Time.deltaTime)

3、使用Lerp函数并用幂指数函数等作为参数,比如

cs 复制代码
1.0 - Mathf.Pow(System.Math.E, - powFactor * System.Math.E * dt)

三、选定方案

最终将调用时机(OnDrag,Update,FixedUpdate,LateUpdate)、插值方式(SmooothDamp,Lerp,LerpPow)以及具体的参数值(smoothTime,lerpFactor , powFactor ) 用不同按钮控制,实现实时调控参数,并打包到安卓测试机上测试。

实现效果最好的是LateUpdate + SmoothDamp + 合适的参数smoothTime 的方式效果最好,因此选择了在LateUpdate读取GetTouch,用SmoothDamp作为插值函数,并到合适的参数。

四、进一步探究

以上的方案其实在Android端已经可以取得相对较佳的表现了,唯一一个问题是,拖动的时候由于有插值延时的逻辑在,拖动地图并没有像iOS那么跟手。

如果希望进一步优化,可以尝试的方向有,在Android原生层使用onTouchEvent事件去获取准确的值,并返回到C#层去使用。但是需要处理和现有事件框架的结合,并做测试。

java 复制代码
@Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        if(action == MotionEvent.ACTION_DOWN){
            long eventTime = event.getEventTime();
            float x = event.getX();
            float y = event.getY();
            Log.d(TAG, "onTouchEvent: ACTION_DOWN " + x + " " + y + " " + eventTime);
        }
        else if(action == MotionEvent.ACTION_MOVE){
            long eventTime = event.getEventTime();
            float x = event.getX();
            float y = event.getY();
            Log.d(TAG, "onTouchEvent: ACTION_MOVE " + x + " " + y + " " + eventTime);
        }
        else if(action == MotionEvent.ACTION_UP){
            long eventTime = event.getEventTime();
            float x = event.getX();
            float y = event.getY();
            Log.d(TAG, "onTouchEvent: ACTION_UP " + x + " " + y + " " + eventTime);
        }
        return super.onTouchEvent(event);
    }

由于时间关系,原生层的优化并没有来得及进行完。后续有结果另行记录。

相关推荐
拭心10 分钟前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
向宇it2 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
带电的小王2 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡3 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道3 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
_oP_i4 小时前
unity webgl部署到iis报错
unity
Go_Accepted4 小时前
Unity全局雾效
unity
向宇it4 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
阿甘知识库4 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道5 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频