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

如果是一个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. win10 环境 gitbash 显示中文乱码问题处理

    gitbash 是 windows 环境下非常好用的命令行终端,可以模拟一下linux下的命令如ls / mkdir 等等,如果使用过程中遇到中文显示不完整或乱码的情况,多半是因为编码问题导致的,修改 ...

  2. NodeJs之log4js

    log4js log4js是一个管理,记录日志的工具. 其实与morgan的作用类似. 安装 npm install -g log4js log4js的6个日志级别 分别是:trace(蓝色).deb ...

  3. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  4. Docker 第一篇--初识docker

    已经多年不写博客, 看完<晓松奇谈>最后一期猛然觉醒, 决定仔细梳理下自己这几年的知识脉络. 既然决定写, 那么首先就从最近2年热门的开源项目Docker开始.Docker 这两年在国内很 ...

  5. 6.DNS公司PC访问外网的设置 + 主DNS服务器和辅助DNS服务器的配置

    网站部署之~Windows Server | 本地部署 http://www.cnblogs.com/dunitian/p/4822808.html#iis DNS服务器部署不清楚的可以看上一篇:ht ...

  6. console的高级使用

    1.console.table()用来表格化展示数据. var people = { zqz: { name: 'zhaoqize', age: 'guess?' }, wdx: { name: 'w ...

  7. 使用Zabbix监控Oracle数据库

    Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...

  8. iOS开发之多种Cell高度自适应实现方案的UI流畅度分析

    本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...

  9. java 利用ManagementFactory获取jvm,os的一些信息--转

    原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...

  10. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...