You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter自定义计时器开发:车辆沿赛道随计时移动并转向

自定义计时器+赛道车辆移动实现方案

1. 赛道路径定义

先把赛道的路径结构化,推荐两种方式:

  • 多点折线路径:适合规则或简单赛道,按顺序记录关键节点坐标
    // 闭环赛道的关键节点数组
    const trackPath = [
      { x: 50, y: 300 },
      { x: 200, y: 100 },
      { x: 400, y: 100 },
      { x: 550, y: 300 },
      { x: 400, y: 500 },
      { x: 200, y: 500 },
      { x: 50, y: 300 } // 回到起点形成闭环
    ];
    
  • 贝塞尔曲线路径:适合平滑曲线赛道,每段记录起点、两个控制点、终点坐标,能实现更自然的弯道效果。

2. 计时与车辆进度映射

核心逻辑是把「剩余时间占总时长的比例」转换成车辆在赛道上的前进进度:

const totalTime = 60; // 总计时时长(秒)
let remainingTime = 60;

// 计算进度:0=起点,1=跑完一圈回到起点
const progress = 1 - (remainingTime / totalTime);
// 多圈场景用取模实现循环:progress % 1

3. 车辆位置计算

折线路径场景

根据进度定位到对应路径段,再用线性插值算出当前坐标:

function getCarPosition(path, progress) {
  const segmentCount = path.length - 1; // 闭环路径的段数
  const currentSegment = Math.floor(progress * segmentCount);
  const segmentProgress = (progress * segmentCount) - currentSegment;

  const startPoint = path[currentSegment];
  const endPoint = path[currentSegment + 1];

  // 线性插值计算当前坐标
  return {
    x: startPoint.x + (endPoint.x - startPoint.x) * segmentProgress,
    y: startPoint.y + (endPoint.y - startPoint.y) * segmentProgress
  };
}

贝塞尔曲线场景

用贝塞尔公式直接计算对应进度的坐标,或者预计算路径上的密集采样点,再通过插值获取位置,保证平滑度。

4. 车辆朝向调整

让车辆朝向与路径前进方向一致,核心是计算路径段的方向向量:

function getCarRotation(path, progress) {
  const segmentCount = path.length - 1;
  const currentSegment = Math.floor(progress * segmentCount);

  const startPoint = path[currentSegment];
  const endPoint = path[currentSegment + 1];

  // 计算方向向量的角度(弧度转角度)
  const dx = endPoint.x - startPoint.x;
  const dy = endPoint.y - startPoint.y;
  return Math.atan2(dy, dx) * 180 / Math.PI;
}

如果是平滑曲线赛道,可以取当前点前后的采样点计算切线方向,让转向更顺滑。

5. 计时更新与渲染循环

用requestAnimationFrame实现持续渲染,同步更新计时和车辆状态:

let startTime = Date.now();
const totalTimeMs = totalTime * 1000;

function update() {
  const elapsedMs = Date.now() - startTime;
  remainingTime = Math.max(0, totalTime - elapsedMs / 1000);

  const progress = 1 - (remainingTime / totalTime);
  const carPos = getCarPosition(trackPath, progress);
  const carRotation = getCarRotation(trackPath, progress);

  // 更新DOM车辆元素的位置与旋转角度
  const carEl = document.getElementById('car');
  carEl.style.left = `${carPos.x}px`;
  carEl.style.top = `${carPos.y}px`;
  carEl.style.transform = `rotate(${carRotation}deg)`;

  if (remainingTime > 0) {
    requestAnimationFrame(update);
  }
}

// 启动计时器与动画
update();

6. 优化建议

  • 预计算路径总长度,用「距离进度」代替段数进度,避免折线赛道各段长度不同导致车辆速度不均
  • 复杂场景优先用Canvas渲染,比DOM元素动画更流畅
  • 加入缓动函数(如线性插值lerp)让车辆的位置和旋转变化更平滑

内容的提问来源于stack exchange,提问作者L.Goyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:10:14