本文系作者原创 转载请注明出处

如果是一个2D的平面项目或者说需要在三维空间选择一个物体时(经常表现为抓取物件),我们需要用到Raycast事件

那么首先先说说什么是Raycast 按照字面上来理解的话,就是投射射线=.=的确也是这样

Raycast有几种重载函数,所以按照惯例,先看看官方文档怎么说的

-------------------------------------------------------------------

Physics.Raycast 光线投射

static function Raycast (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : bool

Parameters参数

  • origin
    The starting point of the ray in world coordinates.
    在世界坐标,射线的起始点。
  • direction
    The direction of the ray.
    射线的方向。
  • distance
    The length of the ray
    射线的长度。
  • layerMask
    A Layer mask that is used to selectively ignore colliders
    when casting a ray.
    只选定Layermask层内的碰撞器,其它层内碰撞器忽略。

Returns返回

bool - True when the ray intersects any collider, otherwise false.

当光线投射与任何碰撞器交叉时为真,否则为假。

Description描述

Casts a ray against all colliders in the scene.

在场景中投下可与所有碰撞器碰撞的一条光线。

Note: This function will return false if you cast a ray from inside a sphere to the outside; this in an intended behaviour.

注意:如果从一个球型体的内部到外部用光线投射,返回为假。

static function Raycast (origin : Vector3, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : bool

Parameters参数

  • origin
    The starting point of the ray in world coordinates.
    在世界坐标,射线的起始点。
  • direction
    The direction of the ray.
    射线的方向。
  • distance
    The length of the ray
    射线的长度。
  • hitInfo
    If true is returned, hitInfo will contain more information
    about where the collider was hit (See Also: RaycastHit).
    如果返回true,hitInfo将包含碰到器碰撞的更多信息。
  • layerMask
    A Layer mask that is used to selectively ignore colliders
    when casting a ray.
    只选定Layermask层内的碰撞器,其它层内碰撞器忽略。

Returns

bool - True when the ray intersects any collider, otherwise false.

当光线投射与任何碰撞器交叉时为真,否则为假。

Description描述

Casts a ray against all colliders in the scene and returns detailed
information on what was hit.

在场景中投下可与所有碰撞器碰撞的一条光线,并返回碰撞的细节信息。

static function Raycast (ray : Ray, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : bool

Parameters参数

  • ray
    The starting point and direction of the ray.
    射线的起点和方向
  • distance
    The length of the ray
    射线的长度。
  • layerMask
    A Layer mask that is used to selectively ignore colliders
    when casting a ray.
    只选定Layermask层内的碰撞器,其它层内碰撞器忽略。

Returns

bool - True when the ray intersects any collider, otherwise false.

当光线投射与任何碰撞器交叉时为真,否则为假。

Description描述

Same as above using ray.origin and ray.direction instead of origin and
direction.

使用ray.origin和ray.direction同上,替代origin和direction。

static function Raycast (ray : Ray, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : bool

Parameters参数

  • ray
    The starting point and direction of the ray.
    射线的起点和方向
  • distance
    The length of the ray
    射线的长度
  • hitInfo
    If true is returned, hitInfo will contain more information
    about where the collider was hit (See Also: RaycastHit).
    如果返回true,hitInfo将包含碰到器碰撞的更多信息。
  • layerMask
    A Layer mask that is used to selectively ignore colliders
    when casting a ray.
    只选定Layermask层内的碰撞器,其它层内碰撞器忽略。

Returns

bool - True when the ray intersects any collider, otherwise false.

当光线投射与任何碰撞器交叉时为真,否则为假。

Description描述

Same as above using ray.origin and ray.direction instead of origin and
direction.

使用ray.origin和ray.direction同上,替代origin和direction

-------------------------------------------------------------------

其中,提到了几个很关键的参数:距离、hitInfo、layerMask

距离,可以用来实现“有效抓取距离”,比如说人的手臂假如说是0.5米长,那我们不能抓到0.5米以外的东西

Layer Mask可以理解为我们用来做标记的物体

而重中之重的是hitInfo,它用来储存我们所投出去的射线的关键信息

比如说射线射到了哪个物体?距离多远?物体的位置?

那么怎么获取它呢?

我们仔细看看Physics.Raycast函数,里面有个参数是out hitInfo,也就是说我们在投射这个射线的时候可以直接利用函数所给的参数获取hitInfo,也就是投出去的射线的关键信息

有了这些背景知识,我们就可以随时用射线实现“选择物体”、“抓取物体”这些动作了(二位尤其需要)

那么现在又出现一个问题,我们怎么去发出这样一条射线??

众所周知,射线从一个固定端点出发,向一个方向无限延伸,我们首先就要找到这个固定端点,然后表示出这个方向简单的是,我们可以用当前的渲染相机作为这个固定端点,因为我们实时在用它观察四周,那么我们所要做的只是找到一个好的投射方向。

请看官方文档里面的一个函数及其解释

-----------------------------------------------------------------------------------------------------------------------------

Camera.ScreenPointToRay 屏幕位置转射线

function ScreenPointToRay (position : Vector3) : Ray

Description描述

Returns a ray going from camera through a screen point.

返回一条从相机发射的,穿过屏幕位置上一点的射线

Resulting
ray is in world space, starting on the near plane of the camera and
going through position's (x,y) pixel coordinates on the screen
(position.z is ignored).

产生的射线是在世界空间中,从相机的近裁剪面发出并穿过屏幕position(x,y)像素坐标(position.z被忽略)。

Screenspace is defined in pixels. The bottom-left of the screen is (0,0); the right-top is (pixelWidth,pixelHeight).

屏幕空间以像素定义。屏幕的左下为(0,0);右上是(pixelWidth,pixelHeight)。

-----------------------------------------------------------------------------------------------------------------------------

请注意特意标出来的红色字体

我们可以看出,它能够返回一条从相机发射的射线,并且函数返回的是一个Ray对象,也就是说我们必须创建一个对象来容纳它

特别注意的是最后几句关于屏幕空间的定义!!

那么现在步骤就清晰了

利用Raycast事件选择一个物体并实现对其的相关操作的步骤:

1.找到一个作为投射起点的相机

2.分别创建两个对象,一个用来容纳返回的射线,一个用来容纳返回的这条射线的所有相关信息(如位置、距离、投射到的物体等)

3.选择这个被射线投射到的物体,之后可以进行相关操作

于是乎放代码了

using UnityEngine;
using System.Collections;

[AddComponentMenu("Raycast/CastObjects")]
public class Raycast_CastObj : MonoBehaviour {

    private GameObject selectedObj=null;
    private Camera validCam;

    //有效触摸距离
    public float validTouchDistance = 5.0F;
    //用户选择的Layer Mask
    public string selectedLayerMask = "Default";

    // Use this for initialization
    void Start ()
    {
        //寻找一个合理的相机
        validCam = FindObjectOfType<Camera>();
        if (validCam == null)
            Debug.LogWarning("Warning!\nFailed to find camera!");
        else
            Debug.Log("Find camera\nName:" + validCam.name);
    }

    // Update is called once per frame
    void Update ()
    {
        var raycast = validCam.ScreenPointToRay(Input.mousePosition);
        RaycastHit raycastInfo;

        if(Physics.Raycast(raycast, out raycastInfo, validTouchDistance, LayerMask.GetMask(selectedLayerMask)))
        {
            //选择这个被射线投射到的物体
            selectedObj = raycastInfo.collider.gameObject;
            Debug.Log("Ray cast to one OBJ\nName:" + selectedObj.name);
        }

        ) && selectedObj)
        {
            //如果射线没有(在用户设置的有效范围内)投射到任何物体
            if (selectedObj == null)
            {
                Debug.Log("Didn't select any Obj\nCheck if it's out of Valid Touch Distance");
            }
            //如果射线(在用户设置的有效范围内)投射到了物体
            else
            {
                Debug.Log("Selected Obj Position in World\n" + selectedObj.transform.position);
            }
        }

        ))
        {
            //必须清空
            selectedObj = null;
        }
    }
}

[Unity3D]利用Raycast实现物体的选择与操作的更多相关文章

  1. JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分)

    JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分) 1.匹配属性的开头 $("[attributeName^='value']"); 2.匹配属性的结尾 ...

  2. C#利用SqlDataAdapte对DataTable进行批量数据操作

    C#利用SqlDataAdapte对DataTable进行批量数据操作,可以让我们大大简化操作数据的代码量,我们几乎不需要循环和不关心用户到底是新增还是修改,更不用编写新增和修改以及删除的SQL语句, ...

  3. Java网络编程:利用apache的HttpClient包进行http操作

    本文介绍如何利用apache的HttpClient包进行http操作,包括get操作和post操作. 一.下面的代码是对HttpClient包的封装,以便于更好的编写应用代码. import java ...

  4. oracle读写文件--利用utl_file包对磁盘文件的读写操作

    oracle读写文件--利用utl_file包对磁盘文件的读写操作 摘要: 用户提出一个需求,即ORACLE中的一个表存储了照片信息,字段类型为BLOB,要求能导出成文件形式. 本想写个C#程序来做, ...

  5. jQuery碎语(1) 基础、选择要操作的元素、处理DOM元素

    1.基础 jquery对象集: $():jquery对象集合 获取jquery对象集中的元素: 使用索引获取包装器中的javascript元素:var temp = $('img[alt]')[0] ...

  6. 利用反射技术实现POJO的数据库操作

    记得第一次写项目的时候,傻傻的数据库一张表,代码里就写一个DAO类,几张表就写几个DAO类,大量的反复代码,自己粘着都嫌烦,后来接触了Hibernate,不得不说对我们这样的小白用处还是非常大的.那么 ...

  7. 利用modelarts和物体检测方式识别验证码

    近来有朋友让老山帮忙识别验证码.在github上查看了下,目前开源社区中主要流行以下几种验证码识别方式: tesseract-ocr模块: 这是HP实验室开发由Google 维护的开源 OCR引擎,内 ...

  8. Unity3D 利用欧拉角实现实体的旋转

    本文系作者原创,转载请注明出处 刚刚入门U3D,也是很多东西搞不懂,最先接触的就是自己尝试去获取键盘上的GetPress之类的事件了吧 官方的API DOC也是帮了不少忙,到处吸收了各位博主的文章也是 ...

  9. 【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动

    背景 上一篇通过鼠标移动的代码很简单,所以看的人也不多,但是还是要感谢“武装三藏”在博客园给出的评论和支持,希望他也能看到第二篇,其实可以很简单,而且是精灵自控制,关键是代码少是我喜欢的方式,也再次印 ...

随机推荐

  1. Ubuntu下使用nvm

    写在前面:刚写着写着博客就跨年了,希望新的一年大家万事如意,一切向"前"看! 安装 wget -qO- https://raw.githubusercontent.com/crea ...

  2. Gradle配置APK自动签名完整流程

    转载请注明出处:http://www.cnblogs.com/LT5505/p/6256683.html 一.生成签名 1.命令行生成签名,输入命令keytool -genkey -v -keysto ...

  3. TortoiseGit 文件比对工具使用 Beyond Compare 和 DiffMerge

    TortoiseGit 内置的文件比对工具是 TortoiseMerge,用于文件比对和解决冲突合并,TortoiseGit 还支持外部的比对工具使用,比如 Beyond Compare 和 Diff ...

  4. ZKWeb网页框架1.2正式发布

    发行日志 https://github.com/zkweb-framework/ZKWeb/blob/master/ReleaseNotes/ReleaseNote.1.2.md 主要改动 更新 ZK ...

  5. 前端自动化构建工具gulp记录

    一.安装 1)安装nodejs 通过nodejs的npm安装gulp,插件也可以通过npm安装.windows系统是个.msi工具,只要一直下一步即可,软件会自动在写入环境变量中,这样就能在cmd命令 ...

  6. 手把手教你写一个RN小程序!

    时间过得真快,眨眼已经快3年了! 1.我的第一个App 还记得我14年初写的第一个iOS小程序,当时是给别人写的一个单机的相册,也是我开发的第一个完整的app,虽然功能挺少,但是耐不住心中的激动啊,现 ...

  7. jQuery禁用或启用

    禁用:.attr("disabled","disabled"); 启用:.removeAttr("disabled");

  8. Kotlin与Android SDK 集成(KAD 05)

    作者:Antonio Leiva 时间:Dec 19, 2016 原文链接:https://antonioleiva.com/kotlin-integrations-android-sdk/ 使用Ko ...

  9. [Android]使用Dagger 2进行依赖注入 - Producers(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6234811.html 使用Dagger 2进行依赖注入 - P ...

  10. osi(open system interconnection)模型的通俗理解

    OSI模型的理解: 以你和你女朋友以书信的方式进行通信为例. 1.物理层:运输工具,比如火车.汽车. 2.数据链路层:相当于货物核对单,表明里面有些什么东西,接受的时候确认一下是否正确(CRC检验). ...