口木说说--第一人称探索交互脚本
发表于2017-10-17
前段时间参加项目做了个第一人称密室解谜的游戏,看了一些插件又添加了些东西,就想把探索交互类的脚本做个整理。
这个脚本块的主体是由一个管理类脚本和一个基类脚本构成,再由基类脚本拓展各个行为类脚本,最后由行为类脚本拓展各个具体脚本。
先看几张图片,理解一下效果是啥样的
基类脚本 (可以一边对着代码看)
- 声明一个公共的枚举类型,如STATIC, PICKUP, ACTIVATE, JOURNAL, INVENTORY等,这里只以这些为例,设置默认类型为STATIC
- 定义一个布尔变量CanInteractWithWhileHoldingObject,判断玩家在拿起物体时是否可与之交互
- 定义一个布尔变量HighlightOnMouseOver,可以勾选是否有物体高亮显示,并赋予对象材质
- 设置一个可交互的最大直线距离
- 设置通用的视线滑过时的提示语
- 在基类脚本中我们要有两个基础方法 设置高亮材质和移除高亮材质,以及一些辅助方法如 获取交互类型、获得CanInteractWithWhileHoldingObject值,也可添加额外的方法,使得某些子类由此功能如discoverObject
管理类脚本
- 定义的变量主要有几个部分
- 检查物体旋转相关变量 包括 旋转速度和起始旋转要求
- 光标 提示 包括 激活和未激活光标的图片及相关布尔变量
- 设置层级 包括 可交互物体层级和放回层级
- 相机焦距 鼠标灵敏度 包括 相机焦距改变的数值和当物体高亮时鼠标灵敏度的设置
- 鼠标提示UI 包括一个用于判断显隐的布尔变量 文字设置 如捡起、放回、丢弃、激活等
- 射线 包括 距离
- 交互设置 包括 三个状态拿着的物体及物体的位置(捡起,检查,放回/丢弃)和当前是否在检查物体的布尔值
- 子类相关变量 包括 日记的按钮设置、音频及文字的设置
2. 因为是用射线法的,所以主要代码都集中在Update中,有多个判断,这部分先这样写。(因为是小项目,没做这部分的优化)
- 判断射线是否碰撞可交互物体
若非可交互物体,与之前操作相同,清除设置。
- 判断拿着物体时的行为
- E或鼠标左键与物体的各种交互 非检查状态
若处在检查等状态,则根据物品类型分情况处理,如激活类型,调用其代码的Active函数;可捡起类型,设置位置、层级、碰撞器、镜头等状态。
- 按下/抬起 左Shift或右键检查/停止检查物体 当前拿着物品
- 根据右键按下 抬起,相机变焦
3. 各种辅助方法
- 光标显隐,鼠标提示显隐,鼠标灵敏度,可移动禁止移动等等
行为类脚本就说两个:
可拾取类型脚本InteractablePickupScript
- 继承基类,重写Awake,设置初始信息
- 重写Update,处理音效
- 可继承函数DoPickupPutdown,处理拾取和放回逻辑,可拓展一些特殊事件
- 私有函数GeneratePutBackPlace,建立放回碰撞器
激活类型脚本InteractableActivateScript
- 继承基类,重写Awake,设置InteractionType类型
- 可继承函数activate,所有子类物体都必须重写此方法,拓展事件
举俩例子
GameCabinetInteractionScript 继承自InteractableActivateScript 控制柜子的交互
public override void activate() { if (cabinet.GetComponent<GameCabinetScript>().isCabinetOpen()) { cabinet.GetComponent<GameCabinetScript>().closeCabinet(); gameObject.GetComponent().clip = cabinetClose; gameObject.GetComponent ().Play(); } else { cabinet.GetComponent<GameCabinetScript>().openCabinet(); gameObject.GetComponent ().clip = cabinetOpen; gameObject.GetComponent ().Play(); } }
GameIdolPickupScript 继承自InteractablePickupScript,拓展了捡起物体触发事件的功能
比如这里 在拿起物体时栅栏升起困住主角,放回物体改变提示
public override void DoPickupPutdown(bool putback) { base.DoPickupPutdown(putback); //一旦被触发捡起放回 可以触发其他事件 //比如这里 构造一个陷阱 详细代码见Update部分 这里只改变bool值 if (pickedUp && !idolRemoved) { idolRemoved = true; startTrap = true; if (!trapTriggerPlate.GetComponent().isPlaying) { trapTriggerPlate.GetComponent ().clip = stoneScrape; trapTriggerPlate.GetComponent ().PlayOneShot(stoneScrape, 5f); } } //当我们放回该放回的地方时 改变物品交互提示 if (putback)//&& !PlayerStatus.isWoodWin) { interactionString = "我把这个手工制品放回去了,差点为这个死了。"; //WoodWin.Instance.TypeWin(); } }
第一次写这些东西,怕自己讲的有误导,还是放代码,代码自己觉得还可以优化。
链接:http://pan.baidu.com/s/1cyHI2M 密码:s6ak