【问题标题】:How to animate a tennis ball to bounce off a horizontal surface如何动画网球从水平表面反弹
【发布时间】:2020-11-09 18:40:10
【问题描述】:

我有一个网球的图像:

有必要制作一个球落下的动画,随后从固体表面反弹。

我得到了这种动画,但看起来不太真实:

要开始动画,请点击图片:

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
<image xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px" >
   <animateTransform attributeName="transform" type="translate" dur="1s" begin="svg1.click" values="0,0;0,168;0" repeatCount="3" />
</image>
   <polyline points="5,190 190,190" stroke="silver" stroke-width="4" />
 
</svg>   

第一次反弹小于球落下的高度,第二次反弹小于第一次反弹的高度,第三次反弹小于第二次。

您是如何做到这一点的?解决方案可能在 SMIL SVG、CSS、JS 上

首选 SMIL SVG 解决方案。

【问题讨论】:

  • 这是一个来自 css-tricks.com 的工作示例 - codepen.io/SaraSoueidan/pen/ecd0f3197b5fc0d7950ed94cc8afb97f
  • @imvain2 非常感谢,我不会删除问题。我也想获得 CSS 和 JS 解决方案。您可以填写您的答案并链接到答案中的来源加上保证,如果没有添加其他解决方案,可能是一个解决方案

标签: javascript html css svg smil


【解决方案1】:

最现实的方法是用 JS 模拟物理。

类似这样的:

let ballElem = document.getElementById("ball");

let GRAVITY = 40;        // Acceleration due to gravity (pixels / sec /sec)
let FLOOR_Y = 200 - 25;  // Y coord of floor. The 25 here is because ball.y is the top of the ball.
let BOUNCINESS = 0.8;    // Velocity retained after a bounce
let LIMIT = 0.1;         // Minimum velocity required to keep animation running
let ball = {};
let lastFrameTime = null;

ballElem.addEventListener("click", startAnim);


function startAnim()
{
  ball = {x: 82, y: 0, dx: 0, dy: 0};
  lastFrameTime = null;
  requestAnimationFrame(animStep);
}


function animStep(timestamp)
{
  if (lastFrameTime === null)
    lastFrameTime = timestamp;
  // Milliseconds elapsed since last step
  const elapsed = timestamp - lastFrameTime;
  lastFrameTime = timestamp;
  
  ball.dy += GRAVITY * elapsed / 1000;
  ball.y += ball.dy;
  ball.x += ball.dx;   // not really used in this example

  if (ball.y > FLOOR_Y) {
    // Step has taken us below the floor, so we need to rebound the ball.
    ball.y -= (ball.y - FLOOR_Y);
    ball.dy = -ball.dy * BOUNCINESS;
  }
  
  // Update the <image> element x and y
  ballElem.x.baseVal.value = ball.x;
  ballElem.y.baseVal.value = ball.y;
  
  // Request another animation step
  if (Math.abs(ball.y - FLOOR_Y) > LIMIT ||  // Not on ground
      Math.abs(ball.dy) > LIMIT ||           // or still moving
      Math.abs(ball.dx) > LIMIT) {
    requestAnimationFrame(animStep);
  }
}
<svg id="svg1" 
     width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
  <image id="ball" xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px"/>
 
</svg>

【讨论】:

  • 非常感谢。您的解决方案对我有用且信息丰富
【解决方案2】:

SVG SMIL 解决方案

可在animateTransform动画命令的values = ""属性中设置可变弹跳量。

可以使用keyTimes 属性的值来控制球在每个时间段的速度。

restart = "whenNotActive" - 在动画完全完成之前防止重新启动动画。

点击后动画会开始

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
<image xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px" >
   <animateTransform id="anT"
     attributeName="transform"
     type="translate"
     dur="3s"
     begin="svg1.click+0.5s"
     values="
      0,0;
        0,168;
        0,84;
        0,168;
        0,126;
        0,168;
        0,148;
        0,168;
        0,158;
        0,168;
        0,163;
        0,168;
        0,166;
        0,168;"
    keyTimes="0;0.066;0.13;0.198;0.264;0.33;0.396;0.462;0.528;0.594;0.66;0.726;0.792;1"
        repeatCount="1"
        fill="freeze"
        restart="whenNotActive" />
</image>
   <polyline points="5,193 194,193" stroke="silver" stroke-width="4" />
 </svg>

循环动画示例

为此,在动画开始条件中写入如下条件:
begin = "svg1.click; anT.end + 1s",其中

svg1.click- 点击后第一次开始动画
anT.end + 1s - 在id = "anT"的动画结束后1秒后重新开始动画

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
<image xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px" >
   <animateTransform id="anT"
     attributeName="transform"
     type="translate"
     dur="3s"
     begin="svg1.click+0.5s;anT.end+1s"
     values="
        0,0;
        0,168;
        0,84;
        0,168;
        0,126;
        0,168;
        0,148;
        0,168;
        0,158;
        0,168;
        0,163;
        0,168;
        0,166;
        0,168;
        "
        keyTimes="0;0.066;0.13;0.198;0.264;0.33;0.396;0.462;0.528;0.594;0.66;0.726;0.792;1"
        repeatCount="1"
        fill="freeze"
        restart="whenNotActive" />
</image>
   <polyline points="5,193 194,193" stroke="silver" stroke-width="4" />
 </svg>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 2011-07-28
    相关资源
    最近更新 更多