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

如何计算GIF动画中方块实现加减速效果的每一帧x坐标值

问题原因

你调整后的代码出现往返运动,是因为位移计算逻辑完全错误:你将匀速位移值直接与当前速度做乘法,当速度随时间下降至0时,x值会从峰值回落至0,自然出现往返效果,不符合位移是随时间累积的基本逻辑。

解决方案

这里提供两种常用实现方案,你可以按需选择:


方案1:动画缓动插值(推荐,易调整)

不需要计算物理参数,直接对运动进度做缓动变换,是动画领域最常用的加减速实现方案:

  • 先计算当前运动进度 $progress,取值范围 0(运动开始)~1(运动结束)
  • 对进度做缓动函数变换,得到缓动后的进度
  • 用缓动进度乘以总距离得到当前x坐标

常用缓动效果对应代码:

  • 减速效果(初速度快,逐渐变慢到停止):$easedProgress = 1 - pow(1 - $progress, 2)
  • 加速效果(初速度慢,逐渐变快):$easedProgress = pow($progress, 2)
  • 先加速后减速:$easedProgress = $progress < 0.5 ? 2 * pow($progress, 2) : 1 - pow(-2 * $progress + 2, 2) / 2

修改后核心代码示例(以减速效果为例):

$fps = 25;
$duration = 2000;
$distance = 100;
$nbFrames = $duration / 1000 * $fps;

$imFrames = new Imagick();
for ($i = 0; $i < $nbFrames; $i++)
{
    $currentTime = $duration / ($nbFrames - 1) * $i;
    // 计算当前进度 0~1
    $progress = $currentTime / $duration;
    // 应用减速缓动
    $easedProgress = 1 - pow(1 - $progress, 2);
    // 计算最终x坐标,限制最大不超过distance避免超出范围
    $x = min($distance, $easedProgress * $distance);
    
    $draw = new ImagickDraw();
    $draw->setFillColor('#ff0000');
    $draw->rectangle(
        $x,
        10,
        $x + 10,
        20
    );
    
    $imFrame = new Imagick();
    $imFrame->newImage(400, 40, '#5b5b5b');
    $imFrame->drawImage($draw);
    $imFrame->setImageDelay(100 / $fps);
    $imFrame->setImageFormat('gif');
    $imFrame->setImageDispose(3);
    
    $imFrames->addImage($imFrame);
}

header('Content-type: image/gif');
$imFrames->setFormat('gif');
echo $imFrames->getImagesBlob();
exit();

方案2:物理匀变速位移公式

如果需要严格符合匀变速物理运动规律,使用正确的位移公式:
x = 初速度 * 时间 + 0.5 * 加速度 * 时间²
注意需要先保证你的参数匹配总位移要求:匀变速运动总位移满足公式 $distance = ($initialVelocity + $finalVelocity) * $duration / 2,参数不匹配的话要么调整参数,要么最后对x做范围限制。

示例代码:

$fps = 25;
$initialVelocity = 100; // 单位px/s,按总位移要求计算得到:2*$distance/$duration = 2*100/2 =100
$finalVelocity = 0;
$duration = 2000; // 单位ms
$distance = 100;
// 加速度单位 px/s²
$acceleration = ($finalVelocity - $initialVelocity) / ($duration / 1000);
$nbFrames = $duration / 1000 * $fps;

$imFrames = new Imagick();
for ($i = 0; $i < $nbFrames; $i++)
{
    $currentTime = $duration / ($nbFrames - 1) * $i;
    $currentTimeSec = $currentTime / 1000;
    // 匀变速位移公式
    $x = $initialVelocity * $currentTimeSec + 0.5 * $acceleration * pow($currentTimeSec, 2);
    // 限制范围避免参数误差导致超出
    $x = max(0, min($distance, $x));
    
    // 后续绘制逻辑不变
    $draw = new ImagickDraw();
    $draw->setFillColor('#ff0000');
    $draw->rectangle(
        $x,
        10,
        $x + 10,
        20
    );
    
    $imFrame = new Imagick();
    $imFrame->newImage(400, 40, '#5b5b5b');
    $imFrame->drawImage($draw);
    $imFrame->setImageDelay(100 / $fps);
    $imFrame->setImageFormat('gif');
    $imFrame->setImageDispose(3);
    
    $imFrames->addImage($imFrame);
}

header('Content-type: image/gif');
$imFrames->setFormat('gif');
echo $imFrames->getImagesBlob();
exit();

内容的提问来源于stack exchange,提问作者Nicolas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:18:02