初始化obs/Unity仓库
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
对于碰撞器而言,基本的碰撞器形状,碰撞器的作用不必多谈,这里着重强调的是碰撞器和触发器,以及他们碰撞和触发的三种状态.
|
||||
### Enter Stay Exit
|
||||
以上三种状态表示了物体碰撞刚刚进入的一帧,物体持续碰撞,和物体离开碰撞的一帧
|
||||
他们分别对应了代码当中的
|
||||
OnCollisionEnter
|
||||
OnCollisionStay
|
||||
OnCollisionExit
|
||||
以及触发器的
|
||||
OnTriggerEnter
|
||||
OnTriggerStay
|
||||
OnTriggerExit
|
||||
他们的用法相同,区别在于方法传入的参数不同
|
||||
碰撞器提供的参数类型是Collision
|
||||
触发器提供的参数类型是Collider
|
||||
### 筛选
|
||||
我们需要在碰撞器和触发器内部进行许多逻辑上的处理,这里有一个关键是如何筛选物体
|
||||
比如NPC和玩家同时触发开门触发器,我们只希望玩家触发时才会开门,需要进行筛选.
|
||||
常见的筛选方法有2种: 签名. 层
|
||||
#### 签名
|
||||
由于为我们提供了参数,我们可以获取到触发的物体,所以我们可以使用签名进行筛选
|
||||
譬如:
|
||||
`if (collision.gameObject.tag==("Player"))`
|
||||
`{`
|
||||
|
||||
`}`
|
||||
`if (collision.gameObject.CompareTag("Tag"))`
|
||||
`{`
|
||||
|
||||
`}`
|
||||
二种方式均可,其中第二种方式的效率更高,因为:
|
||||
Unity将标签单独储存在一个数据结构当中,CompareTag方法可以直接访问该数据结构效率更高.
|
||||
#### 层
|
||||
在Unity当中,层被储存为整数,因此使用层进行筛选的效率比Tag高.
|
||||
层的筛选也需要分为筛选特定的单层,和多层
|
||||
比如你需要玩家单独可以开门,那么就可以使用单层筛选
|
||||
但是如过你想要多个物体都可以开门,那么就需要多层
|
||||
#### 单层检测
|
||||
![[Pasted image 20241219231058.png]]
|
||||
#### 多层检测
|
||||
|
||||
![[Pasted image 20241219231128.png]]
|
||||
|
||||
### **1. 关键概念**
|
||||
|
||||
#### **Layer 和 LayerMask**
|
||||
|
||||
- **Layer(层)**: Unity 中的每个 `GameObject` 都可以设置一个 `Layer`,用于分组、筛选或逻辑处理。每个层的编号是从 `0` 到 `31` 的整数。
|
||||
|
||||
- **LayerMask(层掩码)**: `LayerMask` 是一个 32 位的整型数,每一位(bit)对应一个 Layer。如果某一位是 `1`,则表示该层被包含在掩码中;如果是 `0`,则表示不包含。
|
||||
|
||||
例如:
|
||||
|
||||
- 如果 `LayerMask` 的值是 `5`(即二进制 `00000000 00000000 00000000 00000101`),表示包含第 0 层和第 2 层。
|
||||
- 具体映射:
|
||||
- 第 0 位 = 1 → 包含第 0 层
|
||||
- 第 1 位 = 0 → 不包含第 1 层
|
||||
- 第 2 位 = 1 → 包含第 2 层
|
||||
|
||||
---
|
||||
|
||||
### **2. 拆解逻辑**
|
||||
|
||||
#### **(1) `collision.gameObject.layer`**
|
||||
|
||||
- 获取发生碰撞的对象的层编号(一个整数,例如 `0`、`1`、`2` 等)。
|
||||
|
||||
#### **(2) `(1 << collision.gameObject.layer)`**
|
||||
|
||||
- **位移操作 `<<`**: `1 << x` 表示将 `1` 左移 `x` 位。例如:
|
||||
|
||||
- `1 << 0` → `00000000 00000000 00000000 00000001` (表示第 0 层)
|
||||
- `1 << 2` → `00000000 00000000 00000000 00000100` (表示第 2 层)
|
||||
|
||||
**结果:** 这个操作生成一个位掩码,只有对应层的位置是 `1`,其余位置是 `0`。
|
||||
|
||||
|
||||
#### **(3) `targetLayers | (1 << collision.gameObject.layer)`**
|
||||
|
||||
- **按位或操作 `|`**: 将 `targetLayers` 和生成的位掩码进行按位或运算。
|
||||
|
||||
- 如果 `targetLayers` 中已经包含对应的层(对应位置是 `1`),运算结果不变。
|
||||
- 如果 `targetLayers` 中不包含对应的层(对应位置是 `0`),运算结果会将该位置变为 `1`。
|
||||
|
||||
**例子:**
|
||||
|
||||
- `targetLayers = 00000000 00000000 00000000 00000101` (包含第 0 层和第 2 层)
|
||||
- `collision.gameObject.layer = 1`
|
||||
- `1 << 1 = 00000000 00000000 00000000 00000010` (表示第 1 层)
|
||||
- 运算结果:`00000000 00000000 00000000 00000111` (包含第 0、1 和 2 层)
|
||||
|
||||
#### **(4) 比较:`targetLayers == ...`**
|
||||
|
||||
- 比较 `targetLayers` 和运算结果是否相等。
|
||||
- 如果相等,说明碰撞对象的 `Layer` 已经在 `targetLayers` 中。
|
||||
- 如果不相等,说明碰撞对象的 `Layer` 不在 `targetLayers` 中。
|
||||
|
||||
---
|
||||
|
||||
### **3. 具体判断逻辑**
|
||||
|
||||
代码的核心逻辑是:
|
||||
|
||||
1. 通过 `1 << collision.gameObject.layer` 获取碰撞对象的层对应的位掩码。
|
||||
2. 用 `targetLayers | ...` 检查碰撞对象的层是否在 `targetLayers` 中。
|
||||
3. 如果运算结果和 `targetLayers` 相等,说明碰撞对象的层已经被包含。
|
||||
|
||||
**简化版本:** `(targetLayers | (1 << collision.gameObject.layer))` 实际上就是在“试探性”地将碰撞对象的层加入 `targetLayers`,然后检查是否变化。如果没有变化,说明碰撞对象的层已经在 `targetLayers` 中。
|
||||
|
||||
---
|
||||
|
||||
### **4. 更直观的判断方式**
|
||||
|
||||
可以使用 `LayerMask` 的内置方法 `LayerMask.Contains`(在较新 Unity 版本中),或者稍微改写代码,提升可读性:
|
||||
|
||||
#### 替代写法:
|
||||
|
||||
csharp
|
||||
|
||||
复制代码
|
||||
|
||||
`if (((1 << collision.gameObject.layer) & targetLayers) != 0) { // 进行内部逻辑 }`
|
||||
|
||||
#### **逻辑解析:**
|
||||
|
||||
- `(1 << collision.gameObject.layer)` 生成碰撞对象层的位掩码。
|
||||
- `&`(按位与)检测目标层掩码是否包含该层。
|
||||
- 如果结果不为 `0`,说明目标层掩码包含碰撞对象的层。
|
||||
|
||||
Reference in New Issue
Block a user