fly-barrage 前端弹幕库(5):高级弹幕的设计与实现

本文详细介绍了高级弹幕库中的高级弹幕类(SeniorBarrage),包括其构造函数、关键数据计算方法,以及如何根据视频播放时间动态获取并计算渲染位置。内容涉及高级弹幕的配置、运动阶段划分和位置计算策略。
摘要由CSDN通过智能技术生成

项目官网地址:https://fly-barrage.netlify.app/
👑🐋🎉如果感觉项目还不错的话,还请点下 star 🌟🌟🌟。
Gitee:https://gitee.com/fei_fei27/fly-barrage(Gitee 官方推荐项目);
Github:https://github.com/feiafei27/fly-barrage

其他系列文章:
fly-barrage 前端弹幕库(1):项目介绍
fly-barrage 前端弹幕库(2):弹幕内容支持混入渲染图片的设计与实现
fly-barrage 前端弹幕库(3):滚动弹幕的设计与实现
fly-barrage 前端弹幕库(4):顶部、底部弹幕的设计与实现

高级弹幕的计算是最简单的,因为每个高级弹幕和其他弹幕是无交互的,不需要处理相互重叠的问题,只需要根据当前视频的播放时间计算出高级弹幕处于的位置即可。

1:相关类型

/**
 * 用于描述高级弹幕
 */
export default class SeniorBarrage extends BaseBarrage {
  constructor(seniorBarrageOptions: SeniorBarrageOptions, barrageRenderer: BarrageRenderer) {}
}

export type SeniorBarrageOptions = BaseBarrageOptions & {
  // 弹幕的类型
  barrageType: 'senior';
  // 高级弹幕配置
  seniorBarrageConfig: SeniorBarrageConfig;
}

/**
 * 用于描述二位平面中的一点(单位 px)
 */
export type Location = {
  x: number;
  y: number;
}

/**
 * 用于描述二位平面中的一点(面向用户)
 */
export type LocationDefine = Location & {
  // 定义的类型:直接像素 或 canvas 百分比
  type?: 'PIXEL' | 'PERCENT';
  // 在 x、y 定义的基础上进行坐标偏移
  offsetX?: number;
  offsetY?: number;
}

/**
 * 用于描述高级弹幕的运动配置
 */
export type SeniorBarrageConfig = {
  // 起始点
  startLocation: LocationDefine;
  // 结束点
  endLocation: LocationDefine;
  // 生存时间(单位为毫秒)(数据要求:> 0)
  totalDuration: number;
  // 延迟时间(单位为毫秒)(数据要求:>= 0)
  delay: number;
  // 运动时长(单位为毫秒)(数据要求:>= 0)
  motionDuration: number;
}

高级弹幕的运动分为三部分:

  • 运动前(此时位置一定是在 startLocation);
  • 运动时(根据运动时间、运动速度以及 startLocation 可以计算出来);
  • 运动完成(此时的位置 endLocation);

2:高级弹幕关键数据的计算

export default class SeniorBarrage extends BaseBarrage {
  constructor(seniorBarrageOptions: SeniorBarrageOptions, barrageRenderer: BarrageRenderer) {
    this.calcActualLocation();
  }

  /**
   * 计算关键点的实际坐标
   */
  calcActualLocation() {
    const { startLocation, endLocation, motionDuration } = this.seniorBarrageConfig;

    // 计算实际起始点的位置
    // 计算 actualStartLocation
    let actualStartLocationX = (startLocation.type || 'PIXEL') === 'PIXEL' ? startLocation.x : startLocation.x * this.canvasSize.width;
    let actualStartLocationY = (startLocation.type || 'PIXEL') === 'PIXEL' ? startLocation.y : startLocation.y * this.canvasSize.height;
    if (startLocation.offsetX) actualStartLocationX += startLocation.offsetX;
    if (startLocation.offsetY) actualStartLocationY += startLocation.offsetY;
    this.actualStartLocation = {
      x: actualStartLocationX,
      y: actualStartLocationY
    };
    // 计算 actualEndLocation
    let actualEndLocationX = (endLocation.type || 'PIXEL') === 'PIXEL' ? endLocation.x : endLocation.x * this.canvasSize.width;
    let actualEndLocationY = (endLocation.type || 'PIXEL') === 'PIXEL' ? endLocation.y : endLocation.y * this.canvasSize.height;
    if (endLocation.offsetX) actualEndLocationX += endLocation.offsetX;
    if (endLocation.offsetY) actualEndLocationY += endLocation.offsetY;
    this.actualEndLocation = {
      x: actualEndLocationX,
      y: actualEndLocationY
    };

    // 根据实际起始点的位置,计算 vx 和 vy
    this.vx = (this.actualEndLocation.x - this.actualStartLocation.x) / motionDuration;
    this.vy = (this.actualEndLocation.y - this.actualStartLocation.y) / motionDuration;
  }
}

这里根据用户提供的配置计算出起始点以及结束点的实际坐标,并根据 运动路程 / 运动时间 计算出运动速度,这些关键数据是在接下来计算高级弹幕实时位置时需要的。

3:获取当前应该渲染的高级弹幕,并计算渲染位置

/**
 * 获取当前应该渲染的高级弹幕
 * @param time 视频播放时间点
 */
getRenderSeniorBarrages(time: number): SeniorBarrage[] {
  // 获取当前能够渲染的高级弹幕
  const renderSeniorBarrages = this.seniorBarrageInstances.filter(barrage =>
    // 当前时间大于等于弹幕的出现时间 并且 当前时间小于等于弹幕的结束时间
    time >= barrage.time &&
    time <= (barrage.time + barrage.seniorBarrageConfig.totalDuration)
  );

  // 遍历计算高级弹幕的 top 和 left
  renderSeniorBarrages.forEach(barrage => {
    const startPoint = barrage.time;
    const delayEndPoint = startPoint + barrage.seniorBarrageConfig.delay;
    const motionEndPoint = delayEndPoint + barrage.seniorBarrageConfig.motionDuration;

    if (time >= startPoint && time <= delayEndPoint) {
      // delay 时间段内(渲染在开始点即可)
      barrage.left = barrage.actualStartLocation.x;
      barrage.top = barrage.actualStartLocation.y;
    } else if (time >= delayEndPoint && time <= motionEndPoint) {
      // motion 时间段内
      // 当前的运动时长
      const motionTime = time - delayEndPoint;
      barrage.left = barrage.actualStartLocation.x + motionTime * barrage.vx;
      barrage.top = barrage.actualStartLocation.y + motionTime * barrage.vy;
    } else {
      // 运动结束时间段内(渲染在结束点即可)
      barrage.left = barrage.actualEndLocation.x;
      barrage.top = barrage.actualEndLocation.y;
    }
  });

  return renderSeniorBarrages;
}

首先根据弹幕的出现时间和 totalDuration 以及当前的 time 过滤出当前应该渲染的高级弹幕。

然后遍历应该渲染的弹幕,进行渲染位置的计算,在这里,先计算出高级弹幕所处于的运动阶段,如果是运动前的话,弹幕的渲染位置就是上文计算好的 actualStartLocation,然后是运动后的话,弹幕的渲染位置就是上文计算好的 actualEndLocation,如果是运动中的话,可以根据运动时间以及速度计算出运动的偏移量,再将偏移量加上起始点的位置即可计算出弹幕此时应该渲染的位置。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值