交互功能实现:类《原神》

本文为实现类似《原神》在世界中与物品、NPC等的交互功能,在此抛砖引玉讲讲自己的实现方案。


实现思路:

   简单版:

      1.射线检测范围内可交互对象(可优化降低性能);

      2.存在交互对象时显示交互界面;

      3.点击交互界面选项进入该选项下一级UI可选交互选项;

      4.点击交互选项实现其对应效果功能。


   升级版:

      射线检测范围内可交互对象(可优化降低性能)

         1.角色设计射线检测方法
         2.设计可交互对象类与对应数据表
      存在交互对象时显示交互界面
         1.显示交互UI,并获取射线检测存储的可交互对象数据
         2.刷新UI的选项信息(图片、文字等)
      点击交互界面选项进入该选项下一级UI可选交互选项,点击可选交互选项实现其对应效果功能
         1.判定当前焦点状态机状态,若为非交互状态,则进入交互状态,并根据当前选项与数据表数据匹配寻找下一级(子级)的可选交互选项,然后刷新显示这些选项。如果为交互状态,则根据当前选项,调用其对应的事件方法。


      再加上亿点点细节
         1.创建数据库表并获取表数据(表文件、对应存储类),组合数据(交互选项与子级选项数据组合绑定一起,方便后续查找、使用);
         2.角色射线检测与滚轮功能(通过“滚轮+按键”来选择当前选项);
         3.设计状态机(可选);
         4.设计互动UI与其具体UI管理类(UI初始化、选项事件注册等);
         5.设计互动选项的事件管理类(管理选项的点击事件);
         6.(难)设计互动UI管理类的具体实现功能(选项信息匹配、显示、滚轮功能的GUI焦点切换等);
         7.在互动选项的事件管理类中对选项功能进行实现;
         8.组合起来然后修bug。


   实现效果

   

交互功能实现:类《原神》


   由于整个代码部分比较复杂,以下展示关键代码,仅供学习参考


   射线检测

    /// <summary>
    /// 每隔一段时间进行检测(几帧)
    /// </summary>
    private void RayCheck() {
        if (!isCanRayCheck) {
            return;
        }
        radiusClock += Time.deltaTime;
        if(radiusClock > timeRadiusCheck) {
            radiusClock = 0;
            //检测
            //重置数据
            ListGoInteractive.Clear();
            ListGoInteractiveId.Clear();
            //射线检测--非常近的距离进行检测
            //PS:需要对想要检测的对象设置好层级layout-FantasySpace
            Collider[] cols = Physics.OverlapSphere(tf.position, radiusCheck,1<< LayerMask.NameToLayer("FantasySpace"));
            //如果存在互动对象
            if (cols.Length > 0) {
                //如果焦点状态机不是Interactive,则显示最外层的互动UI
                if (StateMgr.Instance.GetCurrentState(Machine.FocusMachine)!=State.Interactive)
                {
                    for (int i = 0; i < cols.Length; i++)
                    {
                        //Debug.Log("检测到物体" + cols[i].name);
                        //将范围内所有可互动的对象(继承IInteractive接口)存入List中
                        if (cols[i].gameObject.GetComponent<IInteractive>() != null)
                        {
                            ListGoInteractive.Add(cols[i].gameObject.GetComponent<IInteractive>());
                        }
                    }
                    //如果List存在数据并且不处于具体焦点交互状态,则开启UI(显示最外层交互UI)
                    if (ListGoInteractive.Count > 0)
                    {
                        //初始化保存Id,便于后续UI的访问信息
                        GetListGoInteractiveId();
                        Send.SendMsg(SendType.AppearInteractiveUI, true);
                    }
                }
            }
            else
            {
                //如果没有交互对象,且处于Interactive状态,则重置
                if (StateMgr.Instance.GetCurrentState(Machine.FocusMachine) == State.Interactive) {
                    //没有互动对象,设置焦点状态机为isCtrl
                    StateMgr.Instance.GotoState(StateMgr.Machine.FocusMachine, StateMgr.State.Ctrl);
                }
            }
            //没有检测到可交互对象则隐藏互动UI
            if(cols.Length <= 0)
            {
                //如果List没有数据,则关闭互动UI
                Send.SendMsg(SendType.AppearInteractiveUI, false);
            }
        }
    }//RayCheck_end


   滚轮功能

/// <summary>
    /// 滚轮控制交互选择上下移动
    /// </summary>
    private void MouseScrollCtrl() {
        //滚轮上下滑动
        if (Input.GetAxis("Mouse ScrollWheel") < 0) {
            mouseScroll -= GlobalPropertyMgr.FLO_OPOINT5;
            if (mouseScroll <= -1 * GlobalPropertyMgr.FLO_MOUSESCROLLSPEED) {
                Send.SendMsg(SendType.MouseScrollInteractiveUI, true);
                mouseScroll = 0;
            }
        }
        else if (Input.GetAxis("Mouse ScrollWheel") > 0) {
            mouseScroll += GlobalPropertyMgr.FLO_OPOINT5;
            if (mouseScroll >= GlobalPropertyMgr.FLO_MOUSESCROLLSPEED) {
                Send.SendMsg(SendType.MouseScrollInteractiveUI, false);
                mouseScroll = 0;
            }
        }
    }


    /// <summary>
    /// 根据鼠标滚轮来进行互动选项的上下选择
    /// </summary>
    /// <param name="_objs"></param>
    private void EventMouseScrollInteractiveUI(object[] _objs) {
        print("触发");
        if (_objs[0] == null) {
            Debug.LogError("Wrong");
            ret
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值