【问题标题】:SVG chain of different transform animations on same object同一对象上不同变换动画的 SVG 链
【发布时间】:2019-05-21 06:29:21
【问题描述】:

我正在尝试使用 SVG 创建一个下降的俄罗斯方块块的动画,其中包括平移和旋转该块。我对每一个动作都使用了单独的动画,所以它们看起来尽可能接近游戏。下降的动画有效,但是一旦我尝试旋转该部分,它就不会保持旋转并在下一步移动时恢复到原始旋转 (0)。有什么方法可以让这件作品保持旋转,或者甚至是我可以实现动画的更好方法?

提前感谢您的帮助。

<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="280" height="504" xmlns:xlink="http://www.w3.org/1999/xlink">

<defs>
<g id ="b_lightblue">
        <rect x="20" y="20" width="20" height="20" fill="#00F0F0"/>
        <polyline points="20 20, 16 16, 44 16, 40 20, 20 20" fill="#B3FBFB"/>
        <polyline points="40 20, 44 16, 44 44, 40 40, 40 20" fill="#00D8D8"/>
        <polyline points="40 40, 44 44, 16 44, 20 40, 40 40" fill="#007878"/>
        <polyline points="20 40, 16 44, 16 16, 20 20, 20 40" fill="#00D8D8" />
</g>   
<g id ="tetro_I">
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(-16 -16)"/>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(12 -16)"/>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(40 -16)"/>
        <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(68 -16)"/>    
</g>
</defs>

<rect x="0" y="0" width="280" height="504" fill="#CDCEAE"/> <!--Background-->
<use id="tetro_1" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#tetro_I" transform="translate(84 28) rotate(0)" opacity="1"/> <!--Tetris Piece-->

<animateTransform xlink:href="#tetro_1" id="t1_move_1" attributeName="transform" type="translate" begin="0.8s" dur="0.02" from="84 28" to="84 65" fill="freeze"/> 
<animateTransform xlink:href="#tetro_1" id="t1_move_2" attributeName="transform" type="translate" additive="sum" begin="t1_move_1.end+0.8s" dur="0.02" to="84 65" fill="freeze"/>
<animateTransform xlink:href="#tetro_1" id="t1_move_3" attributeName="transform" type="translate" additive="sum" begin="t1_move_2.end+0.8s" dur="0.02" to="84 93" fill="freeze"/>
<animateTransform xlink:href="#tetro_1" id="t1_rotate_1" attributeName="transform" type="rotate" additive="sum" begin="t1_move_3.end+0.2s" dur="0.001" from="0" to="90 56 0" fill="freeze"/>
<animateTransform xlink:href="#tetro_1" id="t1_move_4" attributeName="transform" type="translate" additive="sum" begin="t1_move_3.end+0.8s" dur="0.02" to="84 121" fill="freeze"/>

</svg>

【问题讨论】:

    标签: animation svg svg-animate smil


    【解决方案1】:

    如果您使用具有to 属性但没有from 的动画,则使用的起始值是当前属性值。对于每一步,上一步中的frozen 值将被删除并作为隐式from 重新输入。因此additive="sum" 可能无效。您需要以0 开始每个步骤,然后每次都编写relative 翻译。

    但是您的动画还有其他一些缺陷:首先。 0.02 秒或更短的持续时间只不过是瞬时的。浏览器不使用每秒 60 帧以上的帧速率,这意味着每帧的持续时间为 0.0167 秒。我的建议是在离散的步骤中从一个状态动画到下一个状态并完成它。您可以在keyTimes 列表上将动画编写为values 序列。

    然后必须为每一步绝对编写平移和旋转:

    • 翻译以0 0;0 28;0 65;0 93;0 121 的顺序进行,持续时间为 4 * 0.8 秒
    • 旋转按顺序进行0;0;0;90 56 0;90 56 0,延迟 0.2 秒,但持续时间相同

    第二个问题与应用变换的顺序有关:旋转,当一次应用到已经向下移动的块时,必须使其旋转中心也向下移动,或者必须相乘 翻译的左侧。

    我认为最简单的变体是将块包装在另一个 &lt;g&gt; 元素中,将平移应用于该组,并将旋转应用于内部的 &lt;use&gt; 元素。这样一来,秩序得以保留。

    <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="280" height="504" xmlns:xlink="http://www.w3.org/1999/xlink">
    
    <defs>
    <g id ="b_lightblue">
            <rect x="20" y="20" width="20" height="20" fill="#00F0F0"/>
            <polyline points="20 20, 16 16, 44 16, 40 20, 20 20" fill="#B3FBFB"/>
            <polyline points="40 20, 44 16, 44 44, 40 40, 40 20" fill="#00D8D8"/>
            <polyline points="40 40, 44 44, 16 44, 20 40, 40 40" fill="#007878"/>
            <polyline points="20 40, 16 44, 16 16, 20 20, 20 40" fill="#00D8D8" />
    </g>   
    <g id ="tetro_I">
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(-16 -16)"/>
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(12 -16)"/>
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(40 -16)"/>
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#b_lightblue" transform="translate(68 -16)"/>    
    </g>
    </defs>
    
    <rect x="0" y="0" width="280" height="504" fill="#CDCEAE"/> <!--Background-->
    <g id="tetro_move_1">
      <use id="tetro_rotate_1" xlink:href="#tetro_I" transform="translate(84 0)"/>
    </g> <!--Tetris Piece-->
    
    <animateTransform xlink:href="#tetro_move_1" attributeName="transform" type="translate"
                      begin="0s" dur="3.2s" fill="freeze" additive="sum" calcMode="discrete"
                      values="0 0;0 28;0 65;0 93;0 121"
                      keyTimes="0;0.25;0.5;0.75;1"/> 
    <animateTransform xlink:href="#tetro_rotate_1" attributeName="transform" type="rotate"
                      begin="0.2s" dur="3.2s" fill="freeze" additive="sum" calcMode="discrete"
                      values="0;0;0;90 56 0;90 56 0;"
                      keyTimes="0;0.25;0.5;0.75;1"/> 
    
    </svg>

    【讨论】:

    • 感谢您的详细解释。我之前避免使用 animateTransform,因为我没有完全理解 keyTimes,但现在我明白了。
    • 在您的解释中您说的是 4*0.8s (=3.2s),但在代码中您使用的是 3.6s。这只是一个错字还是我错过了什么?
    • 只是一个错字;-)
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多