You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity安卓第三人称射击:Cinemachine相机触控区域实现与问题修复

修复Unity安卓第三人称射击游戏的触控相机控制问题

问题根源

原脚本存在两个核心问题:

  1. 仅处理单指触摸,未区分触摸ID,导致触摸虚拟摇杆时,脚本仍会识别该触摸并触发相机转动,无法实现同时操作
  2. 未判断触摸是否落在其他UI控件上,点击开火按钮等非相机区域时,触摸状态的异常重置导致视角跳变

修复方案:基于新Input System的实现

以下是适配新Input System的TouchField脚本,支持独立触控区域控制相机,且与虚拟摇杆、其他UI控件无冲突:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;

public class TouchField : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
    [Header("灵敏度设置")]
    public float sensitivityX = 0.1f;
    public float sensitivityY = 0.1f;
    
    [HideInInspector]
    public Vector2 delta; // 用于传递给Cinemachine的视角偏移量
    [HideInInspector]
    public bool isActive; // 当前是否有有效触摸
    
    private int activeTouchId = -1; // 记录当前激活的触摸ID,避免混淆其他触摸
    private Vector2 lastTouchPos; // 上一帧触摸位置

    public void OnPointerDown(PointerEventData eventData)
    {
        // 仅响应未被其他UI占用的触摸
        if (!eventData.IsPointerOverGameObject(eventData.pointerId))
        {
            activeTouchId = eventData.pointerId;
            lastTouchPos = eventData.position;
            isActive = true;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (eventData.pointerId == activeTouchId)
        {
            activeTouchId = -1;
            delta = Vector2.zero;
            isActive = false;
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (eventData.pointerId != activeTouchId) return;
        
        // 计算触摸偏移量
        Vector2 currentPos = eventData.position;
        delta = new Vector2((currentPos.x - lastTouchPos.x) * sensitivityX, 
                           (currentPos.y - lastTouchPos.y) * sensitivityY);
        lastTouchPos = currentPos;
    }

    private void LateUpdate()
    {
        // 每帧结束后重置delta,避免残留值导致视角持续转动
        if (!isActive)
        {
            delta = Vector2.zero;
        }
    }
}

关键修改说明

  • 触摸ID区分:通过activeTouchId记录仅属于当前触控区域的触摸,避免虚拟摇杆的触摸触发相机逻辑
  • UI冲突判断:IsPointerOverGameObject确保触摸未落在其他UI控件上,防止误触发
  • Drag事件处理:改用IDragHandler替代Update中的触摸检测,更符合Unity UI事件体系,避免跳变
  • 自动重置偏移:LateUpdate中重置非激活状态的delta,避免残留值导致视角异常

Cinemachine视角控制代码调整

将原有的Cinemachine参数设置代码替换为以下逻辑,确保仅在有效触摸时更新视角:

// 在Update或LateUpdate中调用
if (touchField.isActive)
{
    povComponent.m_HorizontalAxis.Value += touchField.delta.x * Time.deltaTime;
    povComponent.m_VerticalAxis.Value -= touchField.delta.y * Time.deltaTime;
}

UI区域配置

  1. 在Canvas下创建一个空Image作为相机触控区域,调整RectTransform覆盖你想要的屏幕区域(比如右半屏)
  2. 给该Image添加上述TouchField脚本
  3. 确保该Image的Raycast Target属性为勾选状态,且UI层级低于虚拟摇杆、开火按钮等控件(避免遮挡其他UI的交互)

安卓Unity开发新手建议

  • 优先使用新Input System:新系统对触摸、手柄等输入的支持更统一,避免新旧API混合导致的冲突
  • 真机测试触摸逻辑:模拟器的触摸模拟与真机存在差异,务必在目标安卓设备上测试触控灵敏度和交互逻辑
  • 设置触摸死区:可以在TouchField中添加死区判断,过滤微小的触摸偏移,避免视角误动
  • 适配不同屏幕尺寸:使用Canvas的Scale With Screen Size模式,确保触控区域在不同分辨率下的比例一致
  • 调试触摸事件:在Unity编辑器中使用Input System Debugger窗口查看触摸事件的触发情况,快速定位问题

内容的提问来源于stack exchange,提问作者Areesh Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:22:38