Unity学习90天-第3天-认识触屏输入(手游基础)并完成手机点击屏幕,物体向点击位置移动

一、什么是触屏输入?

手机游戏没有鼠标和键盘,玩家唯一的输入设备就是手指

Unity 把每一次手指触碰屏幕,封装成一个叫做 Touch 的结构体。

Touch 记录了三个核心信息:

  • position 触点位置(手指在屏幕哪里)
  • phase 触摸阶段(手指现在处于什么状态)
  • deltaPosition 移动量(这一帧手指移动了多少)

可以把 Touch 理解为"手指的档案",每根手指有自己的一份档案,随时更新。

二、两个最常用的 API

Update() 里,我们用这两个 API 获取触摸信息:

复制代码
Input.touchCount           // 当前屏幕上有几根手指
Input.GetTouch(index)      // 获取第 index 根手指的 Touch 数据

touchCount 就像数人头------你得先知道"有没有人",再去拿数据。

GetTouch(0) 中的 0 是索引,代表第一根手指(和数组一样,从0开始)。

三、TouchPhase------触摸的五个阶段

这是触屏输入里最重要的概念

每根手指在屏幕上的生命周期分为五个阶段:

阶段 英文枚举 触发时机
按下 TouchPhase.Began 手指刚放上去的那一帧
移动 TouchPhase.Moved 手指在移动的每一帧
静止 TouchPhase.Stationary 手指按着但没动
抬起 TouchPhase.Ended 手指离开屏幕的那一帧
中断 TouchPhase.Canceled 来电话等系统打断

类比:就像开门的过程------推门(Began)→ 门在动(Moved)→ 门停住(Stationary)→ 门关上(Ended)

四、Touch 结构体详解

复制代码
Touch touch = Input.GetTouch(0);

touch.fingerId        // 手指的唯一编号(区分哪根手指)
touch.position        // 屏幕像素坐标,Vector2,左下角是(0,0)
touch.deltaPosition   // 本帧相对上一帧的位移,Vector2
touch.phase           // 当前所处阶段(见上表)
touch.tapCount        // 连续点击次数(单击=1,双击=2)

position 的坐标系是这样的:

(0, 1080)------------------------(1920, 1080)

屏幕中心

(0, 0)---------------------------(1920, 0)

注意:触摸坐标原点在左下角,和 Unity UI 的锚点方向一致。

五、脚本实现------点击检测

那么我们手机触屏的基本知识就已经学完啦,接下来我们来运用知识进行实现脚本吧!

目标:手指点下屏幕时,打印触点的屏幕坐标。

复制代码
using UnityEngine;

public class TapDemo : MonoBehaviour
{
    void Update()
    {
        // 第一步:先判断有没有手指在屏幕上
        if (Input.touchCount > 0)
        {
            // 第二步:取第一根手指的数据
            Touch touch = Input.GetTouch(0);

            // 第三步:只在"按下的那一帧"响应
            if (touch.phase == TouchPhase.Began)
            {
                Debug.Log("点击位置:" + touch.position);
            }
        }
    }
}

为什么要判断 TouchPhase.Began

因为手指放在屏幕上不动,Update() 每帧都会执行。如果不判断 Began,只要手指还按着,就会每帧都打印------这不是我们想要的"点击"效果。

Began 只在放下的那一帧为 true,之后变成 Stationary 或 Moved,所以只会触发一次。

六、脚本实现------点击位置移动

6.1 实现思路拆解

在动手写代码之前,先把这个功能拆解成几个小问题:

  1. 手指点击屏幕 → 获取屏幕坐标(2D像素坐标)
  2. 屏幕坐标 → 转换成世界坐标(3D空间位置)
  3. 物体当前位置 → 平滑移动到目标位置

最关键的一步是第2步------屏幕坐标和世界坐标不是一回事:

坐标类型 单位 示例
屏幕坐标(touch.position) 像素 (540, 960)
世界坐标(物体 Transform) Unity单位 (2.3f, 0, -1.5f)

Unity 提供了转换函数:Camera.main.ScreenToWorldPoint(),帮我们完成这个换算。

6.2 ScreenToWorldPoint------屏幕转世界坐标

复制代码
Camera.main.ScreenToWorldPoint(Vector3 position)

参数说明:

参数 类型 说明
position.x float 触点的屏幕 x 坐标
position.y float 触点的屏幕 y 坐标
position.z float 距相机的深度,必须手动指定

为什么需要 z?因为相机把 3D 世界"拍扁"成了 2D 屏幕,丢失了深度信息。z 就是告诉 Unity:"我要的那个点,在相机前方多远的平面上?"

z 值怎么填?

把物体当前离相机的距离赋给 z,这样转换出来的世界坐标就和物体在同一个深度平面上。

复制代码
// 先算出物体离相机有多远
float distToCamera = Vector3.Distance(transform.position, Camera.main.transform.position);

// 再传给 ScreenToWorldPoint
Vector3 worldPos = Camera.main.ScreenToWorldPoint(
    new Vector3(touch.position.x, touch.position.y, distToCamera)
);

6.3 平滑移动------Vector3.MoveTowards

移动到目标点有两种常见方式:

方式 函数 效果
匀速移动 Vector3.MoveTowards 全程速度一致,到达即停
缓动移动 Vector3.Lerp 越接近目标越慢,丝滑感

在这里我使用 MoveTowards,更适合"点哪走哪"的手游操控感:

复制代码
transform.position = Vector3.MoveTowards(
    transform.position,   // 当前位置
    targetPos,            // 目标位置
    speed * Time.deltaTime // 每帧移动距离
);
  • transform.position:物体当前所在位置
  • targetPos:我们想让它去的位置(点击处)
  • speed * Time.deltaTime:每帧最多走多远(乘以 deltaTime 保证帧率无关)

6.4 脚本总结

在这里我将展示完整的代码给大家以供参考:

复制代码
using UnityEngine;

public class ClickMoveDemo : MonoBehaviour
{
    public float speed = 5f;          // 移动速度
    private Vector3 targetPos;        // 目标位置

    void Start()
    {
        // 初始目标位置就是自身位置(防止一开始就乱跑)
        targetPos = transform.position;
    }

    void Update()
    {
        HandleInput();    // 第一步:处理输入,更新目标点
        MoveToTarget();   // 第二步:每帧向目标点靠近
    }

    // ── 输入处理 ──────────────────────────────
    void HandleInput()
    {
#if UNITY_EDITOR
        // 编辑器里用鼠标左键模拟点击
        if (Input.GetMouseButtonDown(0))
        {
            SetTargetFromScreen(Input.mousePosition);
        }
#else
        // 真机上用触摸
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
        {
            SetTargetFromScreen(Input.GetTouch(0).position);
        }
#endif
    }

    // ── 屏幕坐标 → 世界坐标 → 更新目标点 ─────
    void SetTargetFromScreen(Vector2 screenPos)
    {
        // 用物体到相机的距离作为深度值
        float distToCamera = Vector3.Distance(
            transform.position,
            Camera.main.transform.position
        );

        // 屏幕坐标转世界坐标
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(
            new Vector3(screenPos.x, screenPos.y, distToCamera)
        );

        // 保持 y 轴不变(物体在地面上,不要飞起来或陷地里)
        worldPos.y = transform.position.y;

        targetPos = worldPos;
        Debug.Log("新目标点:" + targetPos);
    }

    // ── 每帧向目标位置移动 ────────────────────
    void MoveToTarget()
    {
        transform.position = Vector3.MoveTowards(
            transform.position,
            targetPos,
            speed * Time.deltaTime
        );
    }
}

七、在编辑器里怎么测试?

真机触屏没法在 PC 编辑器里直接测,用下面这段代码可以一套脚本,编辑器用鼠标,手机用触摸,自动切换:

复制代码
void Update()
{
#if UNITY_EDITOR
    // 编辑器中用鼠标模拟
    if (Input.GetMouseButtonDown(0))
    {
        Debug.Log("【编辑器】点击:" + Input.mousePosition);
    }
#else
    // 真机上用触摸
    if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
    {
        Debug.Log("【真机】点击:" + Input.GetTouch(0).position);
    }
#endif
}

#if UNITY_EDITOR预编译指令 ,Unity 打包到手机时,UNITY_EDITOR 那段代码会被自动剔除,只保留触摸部分。

八、总结

下面我将总结本章的关键函数为表给大家

功能 关键代码
检测有无触摸 Input.touchCount > 0
点击瞬间 touch.phase == TouchPhase.Began
抬起瞬间 touch.phase == TouchPhase.Ended
滑动方向 Ended时 (终点 - 起点)
坐标转世界坐标 Camera.main.ScreenToWorldPoint()

**今天的教学就到这里!**接下来我将连续更新90天的Untiy教程从基础到一个网络部分,有兴趣的朋友们可以收藏关注,谢谢!如果有疑问,评论区见。

成果展示

由于不是真机测试这个博主用的是鼠标模拟屏幕点击,忘记的可以回看Unity学习90天-第2天-认识键盘 / 鼠标输入(PC)并实现WASD 移动,鼠标控制物体转向https://blog.csdn.net/qq_57101277/article/details/160084017?spm=1001.2014.3001.5501

相关推荐
njsgcs2 小时前
获得solidworks 3d零件的包围框 长宽高 boundingbox c#
开发语言·c#·solidworks
青桔柠薯片2 小时前
从字符设备到平台驱动:IMX6ULL LED 与蜂鸣器驱动开发学习总结
驱动开发·学习·imx6ull
JACK的服务器笔记2 小时前
《服务器测试百日学习计划——Day19:PCIe自动检测脚本,用Python把lspci设备清点标准化》
服务器·python·学习
zybsjn2 小时前
异步并发的“流量警察”:在C#中使用SemaphoreSlim进行并发控制的最佳实践
开发语言·c#
南無忘码至尊2 小时前
Unity学习90天-第3天-认识C# 集合与常用类并实现生成随机位置的 10 个立方体
学习·unity·c#
_李小白2 小时前
【OSG学习笔记】Day 47:相机漫游实现
笔记·数码相机·学习
知识分享小能手2 小时前
MongoDB入门学习教程,从入门到精通,MongoDB监控完全指南(22)
数据库·学习·mongodb
~plus~2 小时前
C#/.NET 8 Span与Memory高性能编程完全指南
开发语言·c#·.net
_李小白2 小时前
【OSG学习笔记】Day 46: CameraManipulator(相机操控器)
笔记·数码相机·学习