初始化obs/Unity仓库

This commit is contained in:
2026-05-03 14:06:26 +08:00
commit 0d9e5282f3
95 changed files with 14419 additions and 0 deletions
@@ -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`,说明目标层掩码包含碰撞对象的层。