我正在尝试使用SVG和香草JavaScript制作一个简单的乒乓球游戏。我遇到的问题是,我如何绑定一个事件来确定球的位置何时移动?例如,有没有类似的东西:
document.getElementById("ball").getAttribute("cx").onChange = ...;
我目前构建的代码是:
window.onload = function() {
}
window.onkeydown = function(e){
/*
Player 1:
up -> 38
down -> 40
*/
var increment = 0;
if (e.keyCode === 38 || e.keyCode === 40) {
increment = 5;
if (e.keyCode === 38) {
increment = -increment;
}
}
document.getElementById("paddle1").setAttribute("y", parseFloat(document.getElementById("paddle1").getAttribute("y")) + increment);
};
window.onmousemove = function(e) {
// Player2: Based on the y position of the mouse
document.getElementById("paddle2").setAttribute("y", e.clientY);
}
<svg width="576px" height="300px">
<!-- background -->
<rect x="0" y="0" width="576" height="300" stroke="black" stroke-width="1" />
<!-- ball -->
<circle cx="0" cy="0" r="5" fill="white" id="ball">
<animateMotion path="M 0 150 H 576 Z" dur="5s" repeatCount="indefinite" />
</circle>
<!-- mid-point -->
<line stroke-dasharray="5, 10" x1="287.5" y1="1" x2="287.5" y2="300" stroke="white" stroke-width="1" />
<!-- scores -->
<text x="261" y="27" font-family="monospace" font-size="22px" fill="white" id="score1">0</text>
<text x="298" y="27" font-family="monospace" font-size="22px" fill="white" id="score2">0</text>
<!-- paddles -->
<rect x="10" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle1" />
<rect x="561" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle2" />
</svg>
请记住,虽然我有相当广泛的JavaScript背景,但这是我第一次进入SVG。
动画值更改时似乎不会发出事件,即使是粗粒度(即在给定动画完成百分比的情况下(也不会发出事件。
但是,可以查询当前的动画值,因此定期调用伪处理程序可以在合理的范围内跟踪动画的进度。
以下概念验证独立svg补充并修改了问题中的代码:
- 定义一个间隔处理程序,将球的当前x位置写入控制台
- 在onLoad处理程序中设置间隔处理程序
- 使用
animate
元素重新定义动画
<?xml version="1.0" encoding="UTF-8"?>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 1000 500"
width="1150px" height="600px"
>
<script type="text/javascript">
function cb_ball ( pdom_ball ) {
console.log ( `attr 'cx': '${pdom_ball.cx.animVal.value}'.`);
} // cb_ball
window.onload = function() {
let dom_ball = document.getElementById("ball")
;
setInterval ( () => { cb_ball ( dom_ball ); }, 100 );
}
window.onkeydown = function(e){
/*
Player 1:
up -> 38
down -> 40
*/
var increment = 0;
if (e.keyCode === 38 || e.keyCode === 40) {
increment = 5;
if (e.keyCode === 38) {
increment = -increment;
}
}
document.getElementById("paddle1").setAttribute("y", parseFloat(document.getElementById("paddle1").getAttribute("y")) + increment);
};
window.onmousemove = function(e) {
// Player2: Based on the y position of the mouse
document.getElementById("paddle2").setAttribute("y", e.clientY);
}
</script>
<!-- background -->
<rect x="0" y="0" width="576" height="300" stroke="black" stroke-width="1" />
<!-- ball -->
<circle cx="0" cy="150" r="5" fill="white" id="ball">
<!-- was: animateMotion path="M 0 150 H 576 Z" dur="5s" repeatCount="indefinite" /-->
<animate id="ball-animation"
attributeName="cx"
attributeType="XML"
values = "0;285;570;285;0"
keyTimes="0;0.25;0.5;0.75;1"
calcMode="linear"
dur="5s"
repeatCount="indefinite"
/>
</circle>
<!-- mid-point -->
<line stroke-dasharray="5, 10" x1="287.5" y1="1" x2="287.5" y2="300" stroke="white" stroke-width="1" />
<!-- scores -->
<text x="261" y="27" font-family="monospace" font-size="22px" fill="white" id="score1">0</text>
<text x="298" y="27" font-family="monospace" font-size="22px" fill="white" id="score2">0</text>
<!-- paddles -->
<rect x="10" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle1" />
<rect x="561" y="10" width="5" height="25" stroke="white" stroke-width="1" fill="white" id="paddle2" />
</svg>
参考
该解决方案基于SO问题和以下标准文件:
animateMotion
元素- SVG-IDL
- SVG最小长度
替代方案
anime.js似乎是一个动画库,可以满足问题中列出的需求(参见本节(,对于具有坚实js背景的作者来说是一个部分(我与该库和作者都没有任何关系(。