本文目标:提供 “交互门” 制作思路,对开发中存在的问题给出解答参考。
开发平台:Unity 2018版本以上
编程语言:CSharp 6.0
一、阅读前须知
你必须了解以下内容,以高效率理解 “交互门” 设计思路。
- Unity Animator & Animation 动画系统 | 组件及工具视窗使用
- Unity Physics 物理系统
- Basic CSharp 基础编程语法
—【若文章有遗漏或错误知识,请及时通知博主更新纠正】—
二、交互门的表现形式
分类 | 描述 | 案例 | 附注 |
---|---|---|---|
自动 | 判定条件 集中于 “门” 的交互项 | 感电门 + 感应门 | 参考《Contain Breach》 |
手动 | 偏向于以传递 “媒介” 触发交互门动作 | 密码门 + 权限门 | 参考《Black Mesa》 |
物理 | 以 “玩家” 直接接触的交互行为 | 参考《Human Fallen》 |
- “物理门” 是基于 “物理系统” 下的交互门项。而其他两样更倾向于 “条件” 执行 门动画来表现。
- 个人推荐:
- 非欧几里得世界引擎 | 这是一个很有意思的设计
- 【双语】游戏编程挑战:传送门 Coding Adventure: Portals
三、实践
开发上倾向于使用 “动画” 形式进行门的表现。关于 ”物理门“ 可查阅网络文章配置 Physics 组件 —— 方向 Physics 系统下的 > Joint (关节)组件实现效果。下面主要围绕 “动画” 表现讨论:
3.1 如何通知门该表现其正确的
即使面前摆放着一套带有 开、关,甚至被破坏的完整动画。让其正确的表现成为重中之重。如下所示:大致有两种方式。
应用对象 | 流程 | |
---|---|---|
范围检测 | 集中于 动画门 自身 | 检测范围内对象是否满足条件,并给予反馈 |
射线检测 | 集中于 玩家群 自身 | 由玩家主动探寻对象,传递 “媒介” 等待门反馈 |
参考示意图:
![]() |
![]() |
3.2 关于 范围检测
围绕 “碰撞器” 进行设计。根据其具有的 “触发器” 特性,检测区域内谁进出并予以对应反馈。例如:
public class DoorAccess : MonoBehaviour
{
public void OnTriggerEnter(Collider other)
{
bool isGet = other.gameObject.TryGetComponet(out PlayerInfo output);
if (isGet)
{
if(output.Role == RoleType.Human)
Debug.Log("许可进入|播放开门动画");
}
}
}
如上所示,我要求门在区域检测对象上必须挂载有 PlayerInfo.cs
组件,该组件提供 Role
属性可读,许可 RoleType.Human
的玩家可以触发开门动作。同理我们也可以在 OnTriggerExit
作出对应的关门逻辑。
事实上,在丰富门的触发条件上,并非把所有条件写于方法内。可以了解一些设计模式降低代码冗余。
关于 Collider 说明:
![]() |
![]() |
![]() |
![]() |
Collider
是一个 碰撞器基类。Unity 以此提供 Box|Mesh|Sphere|Capsule Collider 组件。Collider.IsTrigger
需要被检测对象挂在 Collider 组件时可 Trigger 识别
关联CSharp API:
public void OnTriggerEnter | 进入触发器 仅执行一次
public void OnTriggerStay | 在触发器内 每帧执行一次 (可理解持续执行)
public void OnTriggerExit | 离开触发器 仅执行一次
注意:为保证性能最优,使用 OnTriggerEnter
& OnTriggerExit
即可。(获取玩家进出一刻的信息)
3.3 关于 射线检测
围绕 Physics.RayCastHIt
进行设计。由射线碰撞返回对象,执行对应逻辑动画。为保证准确性,一般情况下以 玩家主相机(Main Camera)组件作为射线发射原点。
public void Update()
{
if(Input.GetKeyDown(KeyCode.E))
{
Ray cameraRay = Camera.main.ScreenPointToRay(new Vector2(Screen.Width/2, Screen.Height/2));
bool isRay = Physics.Raycast(cameraRay, out RaycastHit hit);
if (isRay)
{
// 获取对象管理 "交互门" 状态的脚本
// 通知状态改变
}
}
}
- 注意:上述为玩家主观触发,通过按键E触发操作。
- 示例代码存在过渡性能浪费,仅用于参考理解思路。详细性能优化可参考学习网络文章。
射线检测 也可以用于设置信息状态显示,例如:约定射线有效距离。在该距离内,呈现 交互UI 提示可交互。即:
public void Update()
{
Ray cameraRay = Camera.main.ScreenPointToRay(new Vector2(Screen.Width/2, Screen.Height/2));
bool isRay = Physics.Raycast(cameraRay, out RaycastHit hit);
if(isRay)
{
// 通知射线管理中心,处理反馈对应的 交互UI提醒
// ......
// 检查
if (Input.GetKeyDown(KeyCode.E))
{
// 执行效果
}
}
}
- 同上,代码存在性能损耗与设计非最佳。仅供参考。
关联UnityAPI【C#语言】有:
UnityAPI | 说明 |
---|---|
Physics类 | 全局物理属性和物理方法 |
Raycast | 投射光线,从点开始向一个方向投射一定长度,与有碰撞器的物体相撞 |
RaycastHit | 返回射线碰撞信息(需要对象有碰撞器) |
小结
找个时间把这篇远古文章润润。