Unity微信小游戏小窗口模式点击适配

1. 问题描述

项目使用UGUI方案,以点击交互为主。

微信unity方案本身只能调PixelRatio,不能直接调整Unity的分辨率,(还没有测试过"自适应屏幕尺寸"会怎么样),不过看前段时间热门的unity小游戏项目《无尽冬日》也没有对分辨率进行适配,采用了分辨率拉伸的模式。

简单以我自己的手机举例,如果正常打开微信,再打开小游戏,分辨率是1080x2461,如果把小游戏的窗口单独拖到小窗口模式,WeChatWASM.WX.OnWindowResize()的回调给的分辨率是1080x1729,但因为不能调整Unity的分辨率,所以整个画面是拉伸的。反过来,如果先打开微信,把微信拉成小窗口,再打开小游戏,之后再把小游戏全屏,效果会反过来。

画面拉伸问题不算太大,但点击响应的问题比较严重,经过测试,以从左到右为x轴,从下到上为y轴,全屏启动小游戏再拉到小窗口模式后(1080x1729),左上角的输入坐标还是正确的(0,2461), 但左下角的坐标就是错误的(0,732)(2461-1729),导致的现象是越靠近上方的按钮越有可能点对,靠近下方的就点不到了。正确的坐标和输入坐标的关系是

csharp 复制代码
Vector2 GetMousePosition()
{
    var pos = Input.mousePosition;

    int originalHeight = 2461; // 初始化时存储
    int modifiedHeight = 1729; // OnWindowResize() 回调获取
    if (originalHeight == modifiedHeight)
    {
        return pos;
    }

    float resolutionScale = 1; // 分辨率缩放
    float y = pos.y;
    pos.y = (y + (modifiedHeight - originalHeight) * resolutionScale) / modifedHeight * originalHeight;
    return pos;
}

项目用的是旧输入系统,一开始尝试了继承StandaloneInputMoudle进行覆盖,但好像不起作用(也可能是没改对?),最后解决方法是换用了InputSystem,新的输入系统还是比较好用的。

2. 从UnityEngine.Input升级到UnityEngine.InputSystem

  1. 首先要更新UGUI源码(如果使用embbed模式), 虽然版本号一直是1.0.0, 但还是有多次修改的
  2. Window > PackageManager 安装 Input System (本文使用的是1.7.0版本)
  3. Editor > Project Settings > OtherSettings > Active Input Handling, 改为"Input System Package" (关闭旧的输入系统)
  4. UGUI的事件接入: 找到场景中的EventSystem, 把原本的StandaloneUIInputModule删掉, 挂一个InputSystemUIInputModule上去

3. 常用API的直接近似替换

需要注意判空

鼠标:

  • Input.mousePosition -> Mouse.current.position.ReadValue()
  • Input.GetMouseButton(index) -> Mouse.current.leftButton.isPressed | Mouse.current.rightButton.isPressed (下面省略)
  • Input.GetMouseButtonDown(index) -> Mouse.current.leftButton.wasPressedThisFrame
  • Input.GetMouseButtonUp(index) -> Mouse.current.leftButton.wasReleasedThisFrame
  • Input.GetAxis("Mouse ScrollWheel") -> Mouse.current.scroll.ReadValue().y / 120f

键盘(实际只有编辑器在用):

  • Input.GetKey(KeyCode.W) -> Keyboard.current.wKey.isPressed
  • Input.GetKey(keyCode) -> switch case
  • 键盘的Down\Up也是wasPressedThisFrame\wasReleasedThisFrame

另外鼠标的逻辑替换需要注意判断触屏,以Input.mousePosition为例

csharp 复制代码
public static class Input
{
    public static Vector2 mousePosition
    {
        get {
#if !UNITY_EDITOR && UNITY_WEBGL
            var pos = TouchScreen.current?.primaryTouch.position.ReadValue() ?? Vector2.zero;
#else
            var pos = Mouse.current?.position.ReadValue() ?? Vector2.zero;
#endif
            return pos;
        }
    }
}

4. 添加作用到UGUI的坐标转换

为了方便修改,直接把InputSystem包改成embbed模式(包文件夹从Library/PackageCache移动到Packages文件夹)

新建Packages/com.unity.inputsystem@xxx/InputSystem/Controls/Processors/ResolutionVector2Processor.cs

csharp 复制代码
namespace UnityEngine.InputSystem.Processors
{
    public class ResolutionVector2Processor : InputProcessor<Vector2>
    {
        // 这些参数自行找时机传递过来即可
        private static int s_OriginalHeight = 0;
        private static int s_ModifiedHeight = 0;
        private static float s_ResolutionScale = 1.0f;

        public override Vector2 Process(Vector2 value, InputControl control)
        {
            // 和第一节的逻辑相同
            if (s_OriginalHeight == s_ModifiedHeight) return value;

            float y = value.y;
            value.y = (y + (s_ModifiedHeight - s_OriginalHeight) * s_ResolutionScale) / s_ModifiedHeight * s_OriginalHeight;
            return value;
        }

        public override string ToString()
        {
            return $"ResolutionVector2()";
        }
    }
}

Packages/com.unity.inputsystem@xxx/InputSystem/InputManager.cs里面注册一下

csharp 复制代码
internal void InitializeData()
{
    // ...
    processors.AddTypeRegistration("ResolutionVector2", typeof());
    // ...
}

然后在unity中Project窗口选中Packages/com.unity.inputsystem@xxx/InputSystem/Plugins/PlayerInput/DefaultInputActions.inputactions

点击Inspector窗口的Edit asset

ActionMaps选择UI

Actions选择 Point > touch*/position [Touchscreen]

在Processors中添加刚才新建的ResolutionVector2,保存即可

5. Input.mousePosition的替换

回到第3节的代码,把转换逻辑加进去即可

相关推荐
向宇it2 小时前
【unity游戏开发入门到精通——3D篇】3D光源之——unity使用Lens Flare (SRP) 组件实现太阳耀斑镜头光晕效果
游戏·3d·unity·游戏引擎·材质
吴梓穆10 小时前
unity VR linerenderer的线会被UI盖住
unity·vr
枯萎穿心攻击11 小时前
响应式编程入门教程第五节:Unity 生命周期与资源管理中的响应式编程
开发语言·unity·架构·c#·游戏引擎
雷霆嘎子17 小时前
移动游戏性能优化通用技法
游戏·unity
向宇it20 小时前
【实现100个unity特效】unity中使用ShaderGraph实现一个贴图UV循环移动滚动的指示效果
游戏·3d·unity·c#·游戏引擎·贴图·uv
死也不注释1 天前
第三章自定义检视面板_创建自定义编辑器类_实现自定义检视面板中的GUI内容(本章进度(1/9))
unity·编辑器
向宇it1 天前
【unity组件介绍】URP Decal Projector贴花投影器,将特定材质(贴花)投影到场景中的其他对象上。
游戏·3d·unity·c#·游戏引擎·材质
快乐觉主吖2 天前
Unity网络通信的插件分享,及TCP粘包分包问题处理
tcp/ip·unity·游戏引擎
啊基米德3 天前
lua(xlua)基础知识点记录一
unity·lua·xlua