口木说说--第一人称探索交互脚本

发表于2017-10-17
评论6 2.3k浏览

前段时间参加项目做了个第一人称密室解谜的游戏,看了一些插件又添加了些东西,就想把探索交互类的脚本做个整理。

这个脚本块的主体是由一个管理类脚本和一个基类脚本构成,再由基类脚本拓展各个行为类脚本,最后由行为类脚本拓展各个具体脚本。

先看几张图片,理解一下效果是啥样的

基类脚本   (可以一边对着代码看)

  1. 声明一个公共的枚举类型,如STATIC, PICKUP, ACTIVATE, JOURNAL, INVENTORY等,这里只以这些为例,设置默认类型为STATIC
  2. 定义一个布尔变量CanInteractWithWhileHoldingObject,判断玩家在拿起物体时是否可与之交互
  3. 定义一个布尔变量HighlightOnMouseOver,可以勾选是否有物体高亮显示,并赋予对象材质
  4. 设置一个可交互的最大直线距离
  5. 设置通用的视线滑过时的提示语
  6. 在基类脚本中我们要有两个基础方法 设置高亮材质和移除高亮材质,以及一些辅助方法如 获取交互类型、获得CanInteractWithWhileHoldingObject值,也可添加额外的方法,使得某些子类由此功能如discoverObject

 

管理类脚本

  1.  定义的变量主要有几个部分

  • 检查物体旋转相关变量  包括 旋转速度和起始旋转要求
  • 光标 提示  包括 激活和未激活光标的图片及相关布尔变量
  • 设置层级  包括 可交互物体层级和放回层级
  • 相机焦距 鼠标灵敏度  包括 相机焦距改变的数值和当物体高亮时鼠标灵敏度的设置
  • 鼠标提示UI  包括一个用于判断显隐的布尔变量 文字设置 如捡起、放回、丢弃、激活等
  • 射线  包括 距离
  • 交互设置  包括 三个状态拿着的物体及物体的位置(捡起,检查,放回/丢弃)和当前是否在检查物体的布尔值
  • 子类相关变量  包括 日记的按钮设置、音频及文字的设置

   2.  因为是用射线法的,所以主要代码都集中在Update中,有多个判断,这部分先这样写。(因为是小项目,没做这部分的优化)

  •  判断射线是否碰撞可交互物体 
        若是,把当前交互物体设置为射线碰撞物体,再判断如果我没有持有东西,或者持有东西但射线碰撞物体允许在持有物体时进行交互,那么调用基础类中高亮显示函数,并更新右下角鼠标提示;不能交互,则清除设置。
       若非可交互物体,与之前操作相同,清除设置。

  • 判断拿着物体时的行为
       若在检查此物体,因为能拿起的物体都有InteractablePickupScript脚本,根据脚本内的旋转类型进行设置并隐藏鼠标提示

  • E或鼠标左键与物体的各种交互 非检查状态
      若拿着物品,且物品为可放回物品,则把物品放回设置位置,并清空设置,还原数据,若物品为可交互物品且InteractionsAllowedWhenHoldingObjecttrue,则根据物品类型可设置不同方法,可拓展。其他情况,就是丢掉物品,清空设置,还原数据。
      若处在检查等状态,则根据物品类型分情况处理,如激活类型,调用其代码的Active函数;可捡起类型,设置位置、层级、碰撞器、镜头等状态。

  • 按下/抬起 左Shift或右键检查/停止检查物体 当前拿着物品
      停止/恢复 移动,改变物品提示设置旋转信息/还原设置

  • 根据右键按下 抬起,相机变焦
      变焦即改变摄像头的fieldofview
3.  各种辅助方法

  • 光标显隐,鼠标提示显隐,鼠标灵敏度,可移动禁止移动等等

 

行为类脚本就说两个:

可拾取类型脚本InteractablePickupScript

  1. 继承基类,重写Awake,设置初始信息
  2. 重写Update,处理音效
  3. 可继承函数DoPickupPutdown,处理拾取和放回逻辑,可拓展一些特殊事件
  4. 私有函数GeneratePutBackPlace,建立放回碰撞器

激活类型脚本InteractableActivateScript

  1. 继承基类,重写Awake,设置InteractionType类型
  2. 可继承函数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


 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: