同一对象上不同变换动画的 SVG 链
SVG chain of different transform animations on same object
我正在尝试使用 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>
如果您使用具有 to
属性但没有 from
的动画,则使用的起始值是当前属性值。对于每一步,上一步的 frozen
值将被删除并作为隐式 from
重新输入。因此 additive="sum"
不会有任何效果。您需要以 0
开始每个步骤,然后每次都编写 relative 翻译。
但是你的动画还有其他一些缺陷:第一。 0.02 秒或更短的持续时间不过是瞬时的。浏览器不会使用超过每秒 60 帧的帧速率,这意味着每帧的持续时间为 0.0167 秒。我的建议是从一个状态到下一个状态以不连续的步骤设置动画并完成它。您可以将动画编写为 values
的序列,覆盖 keyTimes
.
的列表
然后必须为每个步骤绝对写入平移和旋转:
- 翻译按顺序进行
0 0;0 28;0 65;0 93;0 121
,持续时间为 4 * 0.8s
- 旋转顺序
0;0;0;90 56 0;90 56 0
,延迟 0.2 秒,但持续时间相同
第二个问题与应用变换的顺序有关:旋转,当应用到已经向下移动的块时,必须使其旋转中心也向下移动,或者必须是左侧 的翻译。
我认为最简单的变体是将块包裹在另一个 <g>
元素中,将平移应用于该组并将旋转应用于其中的 <use>
元素。这样,顺序就会得到保留。
<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>
我正在尝试使用 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>
如果您使用具有 to
属性但没有 from
的动画,则使用的起始值是当前属性值。对于每一步,上一步的 frozen
值将被删除并作为隐式 from
重新输入。因此 additive="sum"
不会有任何效果。您需要以 0
开始每个步骤,然后每次都编写 relative 翻译。
但是你的动画还有其他一些缺陷:第一。 0.02 秒或更短的持续时间不过是瞬时的。浏览器不会使用超过每秒 60 帧的帧速率,这意味着每帧的持续时间为 0.0167 秒。我的建议是从一个状态到下一个状态以不连续的步骤设置动画并完成它。您可以将动画编写为 values
的序列,覆盖 keyTimes
.
然后必须为每个步骤绝对写入平移和旋转:
- 翻译按顺序进行
0 0;0 28;0 65;0 93;0 121
,持续时间为 4 * 0.8s - 旋转顺序
0;0;0;90 56 0;90 56 0
,延迟 0.2 秒,但持续时间相同
第二个问题与应用变换的顺序有关:旋转,当应用到已经向下移动的块时,必须使其旋转中心也向下移动,或者必须是左侧 的翻译。
我认为最简单的变体是将块包裹在另一个 <g>
元素中,将平移应用于该组并将旋转应用于其中的 <use>
元素。这样,顺序就会得到保留。
<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>