LineRenderer 、范围检测、射线检测

目录

LineRenderer代码控制相关

LineRenderer练习题

第二题→在Game窗口长按鼠标左键用LineRenderer画出鼠标移动的轨迹

物理系统范围检测

1.盒状范围检测

2.球形范围检测

3.胶囊范围检测

物理系统射线检测

射线检测

得到检测到的信息的API→

3.获取相交的多个物体

练习→在一面墙上点击哪,就生成子弹特效(异步加载资源实现)

关于rigidbody的Is Trigger 和Is Kinematic   的理解->

 
http://t.csdnimg.cn/TgVH2

这周刷了几道双指针题,在洛谷上写了点暴搜题,准备蓝桥杯

LineRenderer代码控制相关

private Material m;

//动态添加一个线段 GameObject line = new GameObject();

line.name = "Line";

LineRenderer lineRenderer = line.AddComponent();

//首尾相连 lineRenderer.loop = true;

//开始结束宽 lineRenderer.startWidth = 0.02f; lineRenderer.endWidth = 0.02f;

//开始结束颜色 lineRenderer.startColor = Color.white; lineRenderer.endColor = Color.red;

//设置材质 m = Resources.Load("M"); lineRenderer.material = m;

//设置点

//一定注意 设置点 要 先设置点的个数

lineRenderer.positionCount = 4;

//接着就设置 对应每个点的位置

lineRenderer.SetPositions(new Vector3[] { new Vector3(0,0,0), new Vector3(0,0,5), new Vector3(5,0,5)});

lineRenderer.SetPosition(3, new Vector3(5, 0, 0));

//是否使用世界坐标系 //决定了 是否随对象移动而移动

lineRenderer.useWorldSpace = false;

//让线段受光影响 会接受光数据 进行着色器计算

lineRenderer.generateLightingData = true;

LineRenderer练习题

第一题:写一个函数,传入一个圆的中心点和半径,用LineRenderer画出一个圆

运用知识点→3D数学,

点加向量,等于让这个点朝向量的方向平移向量的模长

四元数乘以向量→相当于旋转这个向量

void Start()
  {
      DrawCircle(new Vector3(0, 0, 0), 5);
  }

  public void DrawCircle(Vector3 Center,float r)
  {
      GameObject obj = new GameObject();
      obj.name = "Circle";
     LineRenderer lineRenderer = obj.AddComponent<LineRenderer>();
      lineRenderer.positionCount = 360;
      lineRenderer.loop = true;
     for(int i = 0; i < 360; i++)
      {
          lineRenderer.SetPosition(i,Center+ (Quaternion.AngleAxis(i, Vector3.up))*transform.forward*r);
      }

  }

第二题→在Game窗口长按鼠标左键用LineRenderer画出鼠标移动的轨迹

挂载到摄像机上->

  LineRenderer lr;
    void Start()
    {
        
         lr = this.gameObject.AddComponent<LineRenderer>();
        lr.startWidth = 0.1f;
        lr.endWidth = 0.1f;
        lr.loop = false;
        lr.positionCount = 0;
    }
    private void Update()
    {
        if(Input.GetMouseButton(0))
        {
            lr.positionCount += 1;
            Vector3 curPos = Input.mousePosition; //鼠标坐标是二维的
            curPos.z = 10;            
            lr.SetPosition(lr.positionCount - 1, Camera.main.ScreenToWorldPoint(curPos));
        }
    }
}

物理系统范围检测

必备条件:想要被范围检测到的对象 必须具备碰撞器
注意点:
1.范围检测相关API 只有当执行该句代码时 进行一次范围检测 它是瞬时的
2.范围检测相关API 并不会真正产生一个碰撞器 只是碰撞判断计算而已

1.盒状范围检测

参数一:立方体中心点
参数二:立方体三边大小
参数三:立方体角度
参数四:检测指定层级(不填检测所有层)
参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)

Collider[] colliders = Physics.OverlapBox( Vector3.zero, Vector3.one, Quaternion.AngleAxis(45, Vector3.up),

1 << LayerMask.NameToLayer("UI") |

1 << LayerMask.NameToLayer("Default"), QueryTriggerInteraction.UseGlobal);

指定检测的层级是以二进制的每一位代表一层,所以层级最多可以有32层,NameToLayer能够获取对应名字的层级数字,然后让1左移就可以得到对应层级的独一无二的二进制数,在unity内部它会根据我们参数的结果,用结果 & 上每一个层级对应的二进制数,如果返回1则说明要检测该层,否则不检测

拿上面传入的举例,如果UI在第4层(对应十进制16),Default在第0层(对应十进制1),则他们 或 的结果就是0001 0001

然后编辑器内部就会根据0001 0001 来 & 上每个二进制数 , 比如他&上第0层,得到0000 0001,返回1,说明要检测该层, 再&上第四层得到 0001 0000 返回非0,检测该层 ,因为& 上其它层级全部为0,所以其它层级不进行范围检测

根据返回值,我们就可以得到所有检测到的碰撞体的信息,通过遍历的方式

for (int i = 0; i < colliders.Length; i++)

{

print(colliders[i].gameObject.name);

}

盒状范围检测还有一个API返回碰撞到的数量

另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapBoxNonAlloc()
if (Physics.OverlapBoxNonAlloc(Vector3.zero, Vector3.one, colliders) != 0)
{
}

2.球形范围检测

参数一:中心点
参数二:球半径
参数三:检测指定层级(不填检测所有层)
参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
colliders = Physics.OverlapSphere(Vector3.zero, 5, 1 << LayerMask.NameToLayer("Default"));

另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapSphereNonAlloc
if (Physics.OverlapSphereNonAlloc(Vector3.zero, 5, colliders) != 0)
{

}

3.胶囊范围检测

参数一:半圆一中心点 参数二:半圆二中心点 参数三:半圆半径 参数四:检测指定层级(不填检测所有层) 参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息) colliders = Physics.OverlapCapsule(Vector3.zero, Vector3.up, 1, 1 << LayerMask.NameToLayer("UI"), QueryTriggerInteraction.UseGlobal);

另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapCapsuleNonAlloc
if (Physics.OverlapCapsuleNonAlloc(Vector3.zero, Vector3.up, 1, colliders) != 0)
{

}
 

物理系统射线检测

首先需要声明一条射线→

Ray r3 = new Ray(Vector3.zero, Vector3.forward);

参数1是射线的起点,参数二是方向

r3.origin 获取起点

r3.direction 获取方向

2.摄像机发射出的射线
 得到一条从屏幕位置作为起点
 摄像机视口方向为 方向的射线
Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition);

射线检测

进行射线检测 如果碰撞到对象 返回true

参数一:射线 参数二: 检测的最大距离 超出这个距离不检测 参数三:检测指定层级(不填检测所有层) 参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal 返回值:bool 当碰撞到对象时 返回 true 没有 返回false

Ray r3 = new Ray(Vector3.zero, Vector3.forward);

if (Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了对象");
}

**还有一种重载** 不用传入 射线 直接传入起点 和 方向 也可以用于判断
就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了对象2");
}

得到检测到的信息的API→

2.获取相交的单个物体信息
物体信息类 RaycastHit
RaycastHit hitInfo;
参数一:射线
参数二:RaycastHit是结构体 是值类型 Unity会通过out 关键字 在函数内部处理后 得到碰撞数据后返回到该参数中
参数三:距离
参数四:检测指定层级(不填检测所有层)
参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
if (Physics.Raycast(r3, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
    print("碰撞到了物体 得到了信息");

    碰撞器信息
    print("碰撞到物体的名字" + hitInfo.collider.gameObject.name);
    碰撞到的点
    print(hitInfo.point);
    法线信息
    print(hitInfo.normal);

    得到碰撞到对象的位置
    print(hitInfo.transform.position);

    得到碰撞到对象 离自己的距离
    print(hitInfo.distance);

    RaycastHit 该类 对于我们的意义
    它不仅可以得到我们碰撞到的对象信息
    还可以得到一些 碰撞的点 距离 法线等等的信息
}

还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
if (Physics.Raycast(Vector3.zero, Vector3.forward, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{

}

3.获取相交的多个物体

可以得到碰撞到的多个对象
如果没有 就是容量为0的数组
参数一:射线
参数二:能检测的最大距离
参数三:检测指定层级(不填检测所有层)
参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
RaycastHit[] **hits** = Physics.RaycastAll(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
for (int i = 0; i < hits.Length; i++)
{
    print("碰到的所有物体 名字分别是" + hits[i].collider.gameObject.name);
}

还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
之前的参数一射线 通过两个点传入
hits = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);

还有一种函数 返回的碰撞的数量 通过out得到数据
if (Physics.RaycastNonAlloc(r3, **hits**, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal) > 0)  //参数二是RaycastHit类型的数组
{

}

练习→在一面墙上点击哪,就生成子弹特效(异步加载资源实现)

void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100))
{
ResourceRequest rq = Resources.LoadAsync<GameObject>("EffBullet/HitEff");
ResourceRequest rq1 = Resources.LoadAsync<GameObject>("EffBullet/DDD");
rq.completed += (t) =>
{
GameObject obj = (t as ResourceRequest).asset as GameObject;
GameObject dex = Instantiate(obj, hit.point, Quaternion.identity);
Destroy(dex, 2);

};
    rq1.completed += (t) =>
    {
        GameObject obj = (t as ResourceRequest).asset as GameObject;
        GameObject dex = Instantiate(obj, hit.point + hit.normal * 0.5f, Quaternion.identity);
        Destroy(dex, 2);

    };
    print("触发检测");

}


}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值