【threejs】一个控制器事件派发器

更新

个人使用最新版本

export default class Anim {
    constructor(obj, targetObj, options) {
        this.obj = obj;
        this.targetObj = targetObj;
        this.duration = options.duration;
        this.easingFunction = options.easingFunction || Animing.linear;
        this.onUpdate = options.onUpdate;
        this.onComplete = options.onComplete;
        this.repeatInterval = options.repeatInterval || 16; // 默认刷新频率为 16ms (60fps)

        this.initValues();
    }

    initValues() {
        this.startValues = {};
        this.deltaValues = {};

        for (let key in this.targetObj) {
            if (this.targetObj.hasOwnProperty(key)) {
                this.startValues[key] = this.obj[key] || 0; // 默认起始值为 0
                this.deltaValues[key] = this.targetObj[key] - this.startValues[key];
            }
        }
    }

    start() {
        this.startTime = Date.now();
        this.animate();
    }

    startInfinite() {
        this.startTime = Date.now();
        this.isInfinite = true;
        this.animateInfinite();
    }

    animate() {
        const currentTime = Date.now();
        const elapsed = currentTime - (this.startTime || 0);

        if (elapsed < this.duration) {
            // 计算当前进度
            const progress = this.easingFunction(elapsed / this.duration);

            // 更新对象的属性值
            for (let key in this.targetObj) {
                if (this.targetObj.hasOwnProperty(key)) {
                    this.obj[key] = this.startValues[key] + this.deltaValues[key] * progress;
                }
            }

            // 调用更新回调函数
            if (this.onUpdate) {
                this.onUpdate(this.obj);
            }

            // 继续动画
            requestAnimationFrame(() => this.animate());
        } else {
            // 完成动画
            for (let key in this.targetObj) {
                if (this.targetObj.hasOwnProperty(key)) {
                    this.obj[key] = this.targetObj[key];
                }
            }

            // 调用完成回调函数
            if (this.onComplete) {
                this.onComplete(this.obj);
            }
        }
    }

    animateInfinite() {
        const currentTime = Date.now();
        const elapsed = currentTime - (this.startTime || 0);

        // 计算当前进度
        const progress = this.easingFunction(elapsed / this.duration);

        // 更新对象的属性值
        for (let key in this.targetObj) {
            if (this.targetObj.hasOwnProperty(key)) {
                this.obj[key] = this.startValues[key] + this.deltaValues[key] * progress;
            }
        }

        // 调用更新回调函数
        if (this.onUpdate) {
            this.onUpdate(this.obj);
        }

        // 继续动画
        if (this.isInfinite) {
            setTimeout(() => this.animateInfinite(), this.repeatInterval);
        }
    }

    complete() {
        this.isInfinite = false;

        // 完成动画
        for (let key in this.targetObj) {
            if (this.targetObj.hasOwnProperty(key)) {
                this.obj[key] = this.targetObj[key];
            }
        }

        // 调用完成回调函数
        if (this.onComplete) {
            this.onComplete(this.obj);
        }
    }

    static linear(t) {//平滑
        return t;
    }

    static easeInQuad(t) {//渐进
        return t * t;
    }

    static easeOutQuad(t) {//渐出
        return t * (2 - t);
    }

    static easeInOutQuad(t) {//渐进渐出
        return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
    }
    static delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

//使用案例
  lerpCameraPose(defaultVision, duration = 500, _easingFunction = "easeInOutQuad") {
    return new Promise((resolve, reject) => {
      const controls = this.controls;
      if (!controls) return;

      const camera = controls.object; // 当前控制器的相机
      let { position, rotation, target } = defaultVision;
      const startPosition = {
        x: camera.position.x,
        y: camera.position.y,
        z: camera.position.z,
      }

      const anim = new Anim(
        startPosition, position,
        {
          duration: duration,
          easingFunction: Anim[_easingFunction],

          onUpdate: (updated) => {

            console.log(updated);

            camera.position.set(updated.x, updated.y, updated.z)
            if (target) {
              controls.target.set(target.x, target.y, target.z)
            } else {
              camera.rotation.set(rotation.x, rotation.y, rotation.z)
            }
          },
          onComplete: () => {
            if (target) {
              controls.target.set(target.x, target.y, target.z)
              resolve(true)
            }

          }
        }
      )
      anim.start()

      this.dispatchEvent({ type: "viewChange", message: null })
    })
  }

特点

可以为场景内的模型添加点击,鼠标移入移出和鼠标滑动回调

代码


import { EventDispatcher, Raycaster, Vector2, Vector3 } from "three";
// 事件管理器 用于处理事件交互
export class EventManage {
  /**
   *
   *  @param {HTMLElement} dom
   * @param {Camera} camera
   * @param {Scene} scene
   */
  constructor(dom, camera, scene) {
    this.mouse = new Vector2();
    this.raycaster = new Raycaster();
    this.dom = null;
    this.camera = null;
    this.scene = null;
    this.last = null;

    this.listener = [];
    // super()
    this.dom = dom;
    this.camera = camera;
    this.scene = scene;

    const mouse = this.mouse;
    const raycaster = this.raycaster;

    let last = null;
    let lastPos = new Vector3();

    let leftbutton = false;
    let moved = false; // 判断移动参数

    dom.addEventListener("mousemove", (e) => {
      // 阻止事件冒泡
      e.stopPropagation();
      if(!this.camera) return
      let _camera = this.camera
    

      mouse.x = (e.offsetX / dom.offsetWidth) * 2 - 1;
      mouse.y = (-e.offsetY * 2) / dom.offsetHeight + 1;
      raycaster.setFromCamera(mouse, _camera);
      const intersection = raycaster.intersectObjects(this.scene.children);
      if (intersection.length > 0) {
        // console.log(intersection[0]);
        let object = intersection[0].object;
        object.dispatchEvent({
          type: "mousemove",
          point: intersection[0].point,
        });
        if (last && last.uuid == object.uuid) {
        } else {
          if (last)
            last.dispatchEvent({
              type: "mouseout",
              point: intersection[0].point,
            });
          object.dispatchEvent({
            type: "mousein",
            point: intersection[0].point,
          });
        }
        last = object;
        lastPos.copy(intersection[0].point);
      } else {
        if (last) {
          last.dispatchEvent({
            type: "mouseout",
            point: lastPos,
          });
          last = null;
        }
      }

      // 回调执行
      let callbacks = this.listener.filter((item) => item.name == "mousemove");
      if (callbacks.length > 0) {
        callbacks.forEach(({ callback }) =>
          callback({
            object: intersection[0],
          })
        );
      }
      // 防止拖拽旋转后立即触发点击事件
      if (leftbutton) {
        moved = true;
      }
    });
    dom.addEventListener("mouseup", (e) => {
      // 阻止事件冒泡
      e.stopPropagation();
      if(!this.camera) return
      let _camera = this.camera
    
      raycaster.setFromCamera(mouse, _camera);
      const intersection = raycaster.intersectObjects(this.scene.children);
      if (intersection.length > 0) {
        // console.log(intersection[0]);
        intersection[0].object.dispatchEvent({
          type: "mouseup",
          point: intersection[0].point,
        });
      }
      // moved = false
      if (e.button === 0) {
        leftbutton = false;
      }
    });
    dom.addEventListener("mousedown", (e) => {
      // 阻止事件冒泡
      e.stopPropagation();
      if(!this.camera) return
      let _camera = this.camera
      raycaster.setFromCamera(mouse, _camera);
      const intersection = raycaster.intersectObjects(this.scene.children);
      if (intersection.length > 0) {
        // console.log(intersection[0]);
        intersection[0].object.dispatchEvent({
          type: "mousedown",
          point: intersection[0].point,
        });
      }
      if (e.button === 0) {
        leftbutton = true;
      }
    });
    dom.addEventListener("click", (e) => {
      // 阻止事件冒泡
      e.stopPropagation();
      if(!this.camera) return
      let _camera = this.camera
      raycaster.setFromCamera(mouse, _camera);
      const intersection = raycaster.intersectObjects(this.scene.children);
      if (!moved) {
        if (intersection.length > 0) {
          // console.log(intersection[0]);
          intersection[0].object.dispatchEvent({
            type: "click",
            point: intersection[0].point,
          });
        }
        console.log(intersection);

        let callbacks = this.listener.filter((item) => item.name == "click");
        if (callbacks.length > 0) {
          callbacks.forEach(({ callback }) =>
            callback({
              object: intersection[0],
            })
          );
        }
      }
      moved = false;
    });

    // setInterval(() => moved = false, 1)
  }

  addEventListener(name, callback) {
    this.listener.push({ name, callback });
  }

  removeListener(name_, callback_) {
    // let {name,callback} = this.listener
    for (let i = 0; i < this.listener.length; i++) {
      let { name, callback } = this.listener[i];
      if (name === name_ && callback === callback_) {
        this.listener.splice(i, 1);
      }
    }
  }
}

使用

和dom元素添加回调事件一样

	mesh.addEventListener(e,(self)=>callback())
//e : click mousein mouseout mousemove
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸢_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值