当前位置: 首页 > news >正文

美食网站程序推广网站最有效办法

美食网站程序,推广网站最有效办法,网站建设和优化的好处,腾讯科技全真码是什么Unity基础-范围检测 七、范围检测 概述 范围检测(Overlap Detection)是Unity物理系统中的一种常用技术,用于在不产生实际物理碰撞或不依赖刚体的情况下,判断指定区域内是否存在或有哪些碰撞器。它常用于游戏中瞬时的攻击范围判…

Unity基础-范围检测

七、范围检测

概述

范围检测(Overlap Detection)是Unity物理系统中的一种常用技术,用于在不产生实际物理碰撞或不依赖刚体的情况下,判断指定区域内是否存在或有哪些碰撞器。它常用于游戏中瞬时的攻击范围判断、技能效果判定、区域触发等场景,例如:

  • 玩家在前方5米处释放一个范围,检测此范围内的对象是否受到伤害。
  • 玩家攻击,在前方1米圆形范围内检测对象是否受到伤害。
  • 类似这种并没有实体物体,只是想检测在指定某一范围是否让敌方受到伤害时便可以使用。

简而言之,在指定位置进行范围判断,我们可以得到处于指定范围内的对象,目的是对这些对象进行处理(比如受伤、减血等)。

必备条件与注意点

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

层级 (LayerMask)

在进行范围检测时,我们通常需要检测指定层级(Layer)上的物体,以避免检测到不相关的对象,提高效率和精确性。Unity使用位运算来表示层级信息。

  • 通过名字得到层级编号:LayerMask.NameToLayer("LayerName")
  • 层级编号是0~31,刚好32位,是一个int数。
  • 每一个编号都代表二进制的一位。通过将1左移对应层级编号,可以得到该层级的二进制表示。
    • 0 层:1 << 00000 0000 0000 0000 0000 0000 0000 0001 (= 1)
    • 1 层:1 << 10000 0000 0000 0000 0000 0000 0000 0010 (= 2)
    • 2 层:1 << 20000 0000 0000 0000 0000 0000 0000 0100 (= 4)
    • 3 层:1 << 30000 0000 0000 0000 0000 0000 0000 1000 (= 8)
    • 4 层:1 << 40000 0000 0000 0000 0000 0000 0001 0000 (= 16)
  • 好处:一个int就可以表示所有想要检测的层级信息。我们可以通过位运算来选择想要检测的层级。
    • 检测单层:1 << LayerMask.NameToLayer("Default")
    • 检测多层:(1 << LayerMask.NameToLayer("Layer1")) | (1 << LayerMask.NameToLayer("Layer2"))
    • 检测所有层(默认):不传入层级参数,或传入-1

范围检测API

Unity Physics 类提供了一系列范围检测的API。它们通常分为两类:

  • 直接返回Collider[]数组的方法(有GC开销):例如 Physics.OverlapBox,每次调用会创建一个新的数组。
  • 非分配式方法(NonAlloc,无GC开销):例如 Physics.OverlapBoxNonAlloc,需要传入一个预先分配好的Collider[]数组来存储结果,推荐在频繁调用时使用。
1. 盒形范围检测 (Box Overlap)

在指定的一个立方体范围内检测所有碰撞体。

  • Physics.OverlapBox(center, halfExtents, orientation, layerMask)

    • center:立方体的中心点(世界坐标)。
    • halfExtents:立方体各边一半的长度(Vector3)。
    • orientation:立方体的旋转(Quaternion)。
    • layerMask:可选参数,要检测的层级(int)。
    • 返回值Collider[]数组,包含在该范围内的所有碰撞器。
  • Physics.OverlapBoxNonAlloc(center, halfExtents, results, orientation, layerMask)

    • results:预先分配好的Collider[]数组,用于存储检测结果。
    • 返回值int,表示实际检测到的碰撞器数量。

示例代码:

// 声明一个Collider数组用于NonAlloc方法
Collider[] boxColliders = new Collider[10]; // 使用OverlapBox(会产生GC)
Collider[] detectedColliders = Physics.OverlapBox(transform.position + Vector3.forward * 1, Vector3.one / 2, Quaternion.identity, 1 << LayerMask.NameToLayer("Default"));
if (detectedColliders.Length > 0)
{Debug.Log($"OverlapBox检测到 {detectedColliders.Length} 个碰撞体。");
}// 使用OverlapBoxNonAlloc(无GC)
int numColliders = Physics.OverlapBoxNonAlloc(transform.position + Vector3.forward * 1, Vector3.one / 2, boxColliders, Quaternion.identity, 1 << LayerMask.NameToLayer("Default"));
if (numColliders > 0)
{Debug.Log($"OverlapBoxNonAlloc检测到 {numColliders} 个碰撞体。");for (int i = 0; i < numColliders; i++){Debug.Log($"  - {boxColliders[i].name}");}
}
2. 球形范围检测 (Sphere Overlap)

在指定的一个球形范围内检测所有碰撞体。

  • Physics.OverlapSphere(position, radius, layerMask)

    • position:球体的中心点(世界坐标)。
    • radius:球体的半径。
    • layerMask:可选参数,要检测的层级(int)。
    • 返回值Collider[]数组,包含在该范围内的所有碰撞器。
  • Physics.OverlapSphereNonAlloc(position, radius, results, layerMask)

    • results:预先分配好的Collider[]数组。
    • 返回值int,表示实际检测到的碰撞器数量。

示例代码:

// 声明一个Collider数组用于NonAlloc方法
Collider[] sphereColliders = new Collider[10];// 使用OverlapSphere(会产生GC)
Collider[] detectedSphereColliders = Physics.OverlapSphere(transform.position + Vector3.down * 1, 10f, 1 << LayerMask.NameToLayer("Default"));
if (detectedSphereColliders.Length > 0)
{Debug.Log($"OverlapSphere检测到 {detectedSphereColliders.Length} 个碰撞体。");
}// 使用OverlapSphereNonAlloc(无GC)
int numSphereColliders = Physics.OverlapSphereNonAlloc(transform.position + Vector3.down * 1, 10f, sphereColliders, 1 << LayerMask.NameToLayer("Default"));
if (numSphereColliders > 0)
{Debug.Log($"OverlapSphereNonAlloc检测到 {numSphereColliders} 个碰撞体。");for (int i = 0; i < numSphereColliders; i++){Debug.Log($"  - {sphereColliders[i].name}");}
}
3. 胶囊范围检测 (Capsule Overlap)

在指定的一个胶囊体范围内检测所有碰撞体。

  • Physics.OverlapCapsule(point1, point2, radius, layerMask)

    • point1:胶囊体底部半球的中心点(世界坐标)。
    • point2:胶囊体顶部半球的中心点(世界坐标)。
    • radius:胶囊体的半径。
    • layerMask:可选参数,要检测的层级(int)。
    • 返回值Collider[]数组,包含在该范围内的所有碰撞器。
  • Physics.OverlapCapsuleNonAlloc(point1, point2, radius, results, layerMask)

    • results:预先分配好的Collider[]数组。
    • 返回值int,表示实际检测到的碰撞器数量。

示例代码:

// 声明一个Collider数组用于NonAlloc方法
Collider[] capsuleColliders = new Collider[10];// 使用OverlapCapsule(会产生GC)
Collider[] detectedCapsuleColliders = Physics.OverlapCapsule(transform.position, transform.position + Vector3.forward * 5, 0.5f, 1 << LayerMask.NameToLayer("Default"));
if (detectedCapsuleColliders.Length > 0)
{Debug.Log($"OverlapCapsule检测到 {detectedCapsuleColliders.Length} 个碰撞体。");
}// 使用OverlapCapsuleNonAlloc(无GC)
int numCapsuleColliders = Physics.OverlapCapsuleNonAlloc(transform.position, transform.position + Vector3.forward * 5, 0.5f, capsuleColliders, 1 << LayerMask.NameToLayer("Default"));
if (numCapsuleColliders > 0)
{Debug.Log($"OverlapCapsuleNonAlloc检测到 {numCapsuleColliders} 个碰撞体。");for (int i = 0; i < numCapsuleColliders; i++){Debug.Log($"  - {capsuleColliders[i].name}");}
}

实际应用示例:WASD移动与多类型范围检测

这个示例提供一个PlayController脚本,用于控制一个游戏对象的移动,并实现三种不同形状的碰撞范围检测:盒形、胶囊体和球形。移动通过Transform.Translate实现,碰撞检测则利用Unity的Physics.Overlap系列方法。

核心思想:

  • WASD 移动控制:通过获取水平和垂直输入,使用Transform.Translate方法实现游戏对象的移动。
  • 多种碰撞检测
    • Physics.OverlapBox:用于检测一个指定盒子范围内的所有碰撞体。
    • Physics.OverlapCapsule:用于检测一个指定胶囊体范围内的所有碰撞体。
    • Physics.OverlapSphere:用于检测一个指定球形范围内的所有碰撞体。
  • LayerMask (层掩码):用于过滤碰撞检测,只检测指定层上的对象,提高效率和精度。

代码实现 (PlayController.cs)

点击展开/折叠 PlayController.cs 代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayController : MonoBehaviour
{// 用于存储移动向量private Vector3 movement;// 移动速度,可在Inspector面板中调整public float moveSpeed = 2f; // 用于存储碰撞检测结果的Collider数组,预设大小为10个,避免频繁GCprivate Collider[] colliders = new Collider[10];// Update是MonoBehaviour的生命周期函数,每帧调用一次void Update(){// 处理对象的移动逻辑HandleMovement();// 处理对象的碰撞检测逻辑HandleOverLap();}/// <summary>/// 处理碰撞检测逻辑。/// 根据按键(J、K、L)执行不同类型的范围检测。/// </summary>void HandleOverLap(){// J键按下时执行盒形(Box)范围检测if(Input.GetKeyDown(KeyCode.J)){// Physics.OverlapBox:检测一个立方体范围内的所有碰撞体// transform.position + transform.forward * 1:检测中心点在物体前方1个单位// Vector3.one:检测盒子的尺寸为1x1x1// transform.rotation:检测盒子的旋转与物体当前旋转一致// 1 << LayerMask.NameToLayer("Default"):只检测"Default"层上的物体int numDetected = Physics.OverlapBoxNonAlloc(transform.position + transform.forward * 1, Vector3.one / 2, // 半尺寸,所以实际尺寸是Vector3.onecolliders, transform.rotation, 1 << LayerMask.NameToLayer("Default"));// 清空数组中未检测到的部分for (int i = numDetected; i < colliders.Length; i++){colliders[i] = null;}if (numDetected > 0){Debug.Log($"J键:盒形检测到 {numDetected} 个碰撞体!");}else{Debug.Log("J键:盒形检测未发现碰撞体。");}}// K键按下时执行胶囊体(Capsule)范围检测if(Input.GetKeyDown(KeyCode.K)){// Physics.OverlapCapsule:检测一个胶囊体范围内的所有碰撞体// transform.position:胶囊体的底部中心点// transform.position + transform.forward * 5:胶囊体的顶部中心点,在物体前方5个单位// 0.5f:胶囊体的半径// 1 << LayerMask.NameToLayer("Default"):只检测"Default"层上的物体int numDetected = Physics.OverlapCapsuleNonAlloc(transform.position, transform.position + transform.forward * 5, 0.5f, colliders, 1 << LayerMask.NameToLayer("Default"));// 清空数组中未检测到的部分for (int i = numDetected; i < colliders.Length; i++){colliders[i] = null;}if (numDetected > 0){Debug.Log($"K键:胶囊形检测到 {numDetected} 个碰撞体!");}else{Debug.Log("K键:胶囊形检测未发现碰撞体。");}}// L键按下时执行球形(Sphere)范围检测if(Input.GetKeyDown(KeyCode.L)){// Physics.OverlapSphere:检测一个球形范围内的所有碰撞体// transform.position + Vector3.down * 1:球体的中心点在物体下方1个单位// 10f:球体的半径为10个单位// 1 << LayerMask.NameToLayer("Default"):只检测"Default"层上的物体int numDetected = Physics.OverlapSphereNonAlloc(transform.position + Vector3.down * 1, 10f, colliders, 1 << LayerMask.NameToLayer("Default"));// 清空数组中未检测到的部分for (int i = numDetected; i < colliders.Length; i++){colliders[i] = null;}if (numDetected > 0){Debug.Log($"L键:球形检测到 {numDetected} 个碰撞体!");}else{Debug.Log("L键:球形检测未发现碰撞体。");}}// 如果检测到碰撞体,则遍历并打印所有检测到的碰撞体名称// 这里使用循环来确保只处理实际检测到的数量for(int i = 0; i < colliders.Length; i++){// 确保当前元素不为空才打印if (colliders[i] != null) {Debug.Log($"检测到碰撞体: {colliders[i].name}"); }}}/// <summary>/// 处理移动逻辑。/// 根据WASD键的输入控制物体的移动和旋转。/// </summary>void HandleMovement(){// 获取水平轴(A/D键或左右箭头)的输入float horizontal = Input.GetAxis("Horizontal");// 获取垂直轴(W/S键或上下箭头)的输入float vertical = Input.GetAxis("Vertical");// 基于垂直输入前后移动// Time.deltaTime 用于使移动速度与帧率无关transform.Translate(Vector3.forward * vertical * moveSpeed * Time.deltaTime);// 基于水平输入左右旋转// 旋转速度可以根据moveSpeed调整,或者单独设置一个rotateSpeedtransform.Rotate(Vector3.up * horizontal * moveSpeed * 50 * Time.deltaTime); // 乘以一个系数使旋转更明显}
}

使用建议

  1. 性能优化:在频繁进行范围检测的场景,优先使用NonAlloc系列方法(如OverlapBoxNonAlloc),以避免每次调用都产生新的Collider[]数组,从而减少GC(垃圾回收)开销。
  2. 精确控制:善用LayerMask参数来精确控制只检测特定层级的对象,提高检测效率和准确性。
  3. 调试可视化:在开发过程中,可以使用Debug.DrawBoxDebug.DrawLine等方法来可视化检测范围,帮助理解和调试。
  4. 触发器设置:范围检测通常用于获取范围内的对象信息,而不是模拟物理碰撞。确保被检测对象上的碰撞器如果设置为Is Trigger,则它们不会产生物理交互。
http://www.hkea.cn/news/201758/

相关文章:

  • 手机做网站的步骤跨境电商有哪些平台
  • 请人做网站要多少网络事件营销
  • 网站页脚有什么作用厦门seo哪家强
  • 东莞百度提升优化优化推广网站推荐
  • 查企业网站有哪些站长统计app软件
  • 做a高清视频在线观看网站济源新站seo关键词排名推广
  • 刚做的网站怎么搜索不出来百度seo收录软件
  • 视频拍摄app站长工具seo综合查询广告
  • 新闻单位建设网站的意义武汉seo推广优化
  • 低价网站公司软文怎么写
  • 东莞市建设公共交易中心网站百度官网首页
  • 如何建立的网站能争钱优化营商环境 助推高质量发展
  • 做百度网站营销型网站建设排名
  • 网站域名被黑国际新闻最新消息战争
  • 苏州网站开发公司济南兴田德润厉害吗网络自动推广软件
  • 广药网站建设试卷株洲最新今日头条
  • 网站建设管理考核办法微信推广平台怎么做
  • 网站新闻模块代码网络推广有哪些常见的推广方法
  • 合肥大型网站如何推广普通话
  • 高端网站制作软件怎么样推广自己的店铺和产品
  • 无障碍浏览网站怎么做关键词seo排名优化推荐
  • wordpress 247seo推广系统
  • 做深圳门户网站起什么名字好泰州seo外包公司
  • 网站视频上传怎么做百度站长平台论坛
  • wordpress农业模板下载小时seo
  • 做网站语言排名2018发帖推广哪个平台好
  • 销氪crmseo入门讲解
  • 蒙阴哪有做淘宝网站的钓鱼网站制作教程
  • 网站如何做导航条下拉菜单怎么做百度网页
  • 网站开发都做什么平台推广精准客源