Unity3D RPG Core | 30 创建传送门

这节开始制作传送门,它用作后续的场景传送功能。我们先制作传送门的外观,使用 Shader Graph 制作。

1. 制作传送门效果

传送门效果使用 Shader Graph 制作,Shader Graph 我们在之前的文章 《Unity3D RPG Core | 09 Shader Graph 遮挡剔除》 中已经使用过,可以温习一下。

首先我们在 Assets 窗体中右击 Create - Shader Graph - URP - Lit Shader Graph,创建新的 Shader Graph 进行编辑。

如图 1 所示,我们最先创建 Twirl 节点,它是彩色的旋转 UV,我们使用变量控制它的几个参数。Time 和 Speed 变量相乘传递给 Offset 属性,可以实现动态旋转的效果。Strength 变量传递给 Strength 属性,可以控制旋转的力度(效果上看着是圆圈的相隔)。

Twirl 的输出我们传递给 Voronoi 节点,可以看图上的效果是变成了黑白。使用 CellScale 变量调整它的 Cell Density 属性,从调整的画面上看它也是影响圆圈的密集程度。

最后我们通过 Power 节点将 Voronoi 输出增强一下。

图1 Shader Graph 部分

现在的效果是正方形的,我们需要让它是圆形效果。所以,如图 2 所示,我们添加一张圆形边缘的纹理图,将它和之前 Voronoi 的输出结果相乘。

图2 Shader Graph 部分

现在的效果还是黑白的,我们需要赋予颜色。我们再引入 Color 变量设置颜色(Color 的 Mode 设置为 HDR),和上述的输出相乘。最终的结果连入片段着色器的 Emission 和 Alpha 输入。

要想片段着色器中有 Alpha 通道,我们需要 Graph Settings 中的 Surface Type 属性为 Transparent。同时因为是 3D 场景,需要各个角度都能看到传送门,我们还需要设置双面显示:Render Face 设置为 Both

图3 Shader Graph 部分

连上 Alpha 输入后可能会出现没有结果输出的情况。原因不明,尝试发现和指定的输入颜色有关,可能是运算有溢出导致。

2. 创建传送门

在创建好的 Shader Graph 上右击,选择 Create - Material 可以创建对应的材质。

我们在场景中右击,选择 3D Object - Quad,创建一个四边形,用它当作传送门。接着把创建好的材质拖拽到对象上就可以看到效果了。

要想在 Scene 场景中看到旋转效果,可以使能效果按钮中的 Always Refresh。

接着如图 4 所示,我们调整一下传送门对象的属性。现在 Quad 对象是有影子的,我们可以设置 Cast Shadows 为 Off 关掉。我们将原先的 Mesh Collider 删除掉,换成 Box Collider,并勾选上 Is Trigger,这样才会有触发事件生成。

图4 Quad 对象设置

最后还需要设置传送到的位置,我们通过在传送门对象下添加一个空对象来定位。

3. 传送门脚本

在本节,我们对传送门脚本相关的内容开个头。视频中的设置一开始有点费解,其中是传送门对象下绑定一个脚本,然后传送门对象下的空对象(传送位置点对象)也绑定一个脚本。传送位置点对象脚本定义传送目的地相关的内容,两者彼此分离。

不清楚为什么要特意把传送目的点功能特别分离开,此处把作者的思路理解了一下,自行实现了一番。

如代码清单 1 所示,我们用名字来唯一定义传送门(m_portalName),传送的目的地也是传送门,所以也用名字来定义(m_destinationPortalName)。同时还定义了是同场景传送还是不同场景传送(m_transmissionType),以及场景的名字(m_sceneName)。

函数 OnTriggerStay 和 OnTriggerExit 响应是否进入传送门区域,以此更新 canTransfer 变量,决定是否可以传送。

代码清单 1 传送门控制脚本
  1. public class PortalController : MonoBehaviour
  2. {
  3.     public enum TransmissionType
  4.     {
  5.         TransmissionSameScene,
  6.         TransmissionDifferentScene,
  7.     }
  8.  
  9.     public string m_sceneName;
  10.     public string m_portalName;
  11.     public string m_destinationPortalName;
  12.     public TransmissionType m_transmissionType;
  13.  
  14.     bool canTransfer = false;
  15.  
  16.     private void OnTriggerStay(Collider other)
  17.     {
  18.         if (other.CompareTag("Player"))
  19.         {
  20.             canTransfer = true;
  21.             Debug.Log("OnTriggerStay");
  22.         }
  23.     }
  24.  
  25.     private void OnTriggerExit(Collider other)
  26.     {
  27.         if (other.CompareTag("Player"))
  28.         {
  29.             canTransfer = false;
  30.             Debug.Log("OnTriggerExit");
  31.         }
  32.     }
  33. }

图 5 是传送门的最终效果,可以走进传送门碰撞区域,查看碰撞体触发事件函数的日志是否打印。

图5 传送门效果