A-Frame 组件代码实现 —— draggable-by-ray:利用手柄射线拽取实体

本文介绍了如何在A-Frame框架中使用draggable-by-ray组件,通过手柄触发事件实现对象的拖拽。组件定义了移动速度和最小距离参数,并通过监听trigger事件控制物体的选取和移动。HTML示例展示了如何在场景中应用该组件。
摘要由CSDN通过智能技术生成

A-Frame Components

draggable-by-ray:利用手柄射线拽取实体

  • 全局定义

    • 增加组件依赖,或另外挂载在 a-entity 上

    • raycaster 事件属性方法详见:https://aframe.io/docs/1.5.0/components/raycaster.html#members

    dependencies: ["raycaster"];
    
    • 设置参数及默认值
    schema: {
      speed: { type: "number", default: 5 }, // 移动速度,默认为5米/秒
      minDistance: { type: "number", default: 0.2 }, // 最小距离,默认为0.2米
    },
    
    • 全局变量
    
    init: function () {
      var self = this;
      // 存储选中的实体
      this.selectedEntity = null;
      // 是否按下trigger
      this.isTriggerDown = null;
    }
    
  • 监听手柄 trigger 事件:根据手柄 trigger 事件激活拉取动作

    // 监听trigger按下事件
    this.el.addEventListener("triggerdown", function () {
      self.isTriggerDown = true;
    });
    // 监听trigger释放事件
    this.el.addEventListener("triggerup", function () {
      self.isTriggerDown = false;
    });
    
  • 监听 raycaster 指向事件:更新 raycaster 指向的对象实体

    // 监听 raycaster 指向事件
    this.el.addEventListener("raycaster-intersection", function (evt) {
      // 获取选中的第一个实体
      self.selectedEntity = evt.detail.els[0];
    });
    
    // 监听 raycaster 离开事件,取消选中的实体
    this.el.addEventListener("raycaster-intersection-cleared", function () {
      self.selectedEntity = null;
    });
    
  • tick 渲染

    • 判别是否存在选中的实体、是否按下 trigger

    • 获取手柄位置(终点)

    • 计算移动方向,移动距离,并移动到目标位置

    • 判断终点距离 minDistance,小于 minDistance 则不进行移动

    • 根据方向向量进行每帧平滑移动

    tick: function (time, timeDelta) {
        // 如果存在选中的实体,则平滑移动到手柄位置
        if (this.selectedEntity && this.isTriggerDown) {
    
          // 获取目标位置(手柄位置)
          var targetPosition = this.el.object3D.position.clone();
          // 获取起始位置(选中实体的位置)
          var currentPosition = this.selectedEntity.object3D.position.clone();
    
          //计算两者距离
          var distance = currentPosition.distanceTo(targetPosition);
          // 如果距离小于最小距离,不进行移动
          if (distance < this.data.minDistance) {
            return;
          }
    
          // 计算移动方向
          // 计算三维坐标差,并进行.normalize()归一化,得到单位方向向量
          var direction = targetPosition.clone().sub(currentPosition).normalize();
          // 计算移动距离
          var moveDistance = this.data.speed * (timeDelta / 1000);
    
          // 计算目标位置:当前位置+方向向量*移动距离
          // .multiplyScalar():将向量乘以一个标量,返回一个新的向量。
          var newPosition = currentPosition
            .clone()
            .add(direction.multiplyScalar(moveDistance));
    
          // 设置实体的新位置
          this.selectedEntity.setAttribute("position", newPosition);
        }
      }
    
  • HTML 示例

    <a-scene>
      <a-camera position="0 1.6 0"></a-camera>
      <a-entity id="leftHand" oculus-touch-controls="hand: left"></a-entity>
      <!-- draggable-by-ray挂载 -->
      <a-entity
        id="rightHand"
        laser-controls="hand:right"
        raycaster="objects: .draggable; far: 10"
        draggable-by-ray
      ></a-entity>
      <!-- 设置raycaster的objects类型为draggable -->
      <a-box
        class="draggable"
        id="box"
        position="1 1 -6"
        color="#4CC3D9"
      ></a-box>
      <a-box
        class="draggable"
        id="box"
        position="-1 2 -4"
        color="#FF0000"
      ></a-box>
    </a-scene>
    
  • 40
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值