问题描述
今天晚上,和小伙伴一块用js canvas完成童年回忆坦克大战,做到一半时,发现这样一个问题。当我按住上移动按钮之后同时按住右移动按钮,再松开右按钮,坦克没有向上移动,而是停止了移动,这极其不符合预期效果。
思考
首先,这个问题是由于js是单线程,按键事件监听现有的会覆盖掉之前的,因此不会再触发原有按键事件。
解决方法
我这里提出一个方案:
引入一个全局数组,用于记录已按按键,此数组只允许存储标识按键的值,并且不允许重复值,再到定时器中循环执行数组内对应按键所执行的操作移动操作,定时器循环执行时间间隔为游戏的帧数。
OK,可以开干了
解决demo代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body style="width: 100%;height: 689px;">
<div id="tank" style="position: relative;width: 50px;height: 50px;background-color: aqua;left:100px;top: 100px;"> </div>
<script>
const tank=document.getElementById("tank")
const contrlArr = []
addEventListener("keydown", (e) => {
if ([37, 38, 39, 40].includes(e.keyCode))
{ if (e.keyCode == 37) {
console.log("左"); }
if (e.keyCode == 38) {
console.log("上");
}
if (e.keyCode == 39) {
console.log("右"); }
if (e.keyCode == 40) { console.log("下"); } if (!contrlArr.includes(e.keyCode)) { contrlArr.push(e.keyCode) } } }) addEventListener("keyup", (e) => { if ([37, 38, 39, 40].includes(e.keyCode)) { if (e.keyCode == 37) { console.log("左"); } if (e.keyCode == 38) { console.log("上"); } if (e.keyCode == 39) { console.log("右"); } if (e.keyCode == 40) { console.log("下"); } contrlArr.map((v, i) => { if (v == e.keyCode) { contrlArr.splice(i, 1) } }) } }) // 控制移动帧数 setInterval(()=>{ contrlArr.map((v,i)=>{ if(contrlArr.length&&contrlArr.length==(i+1)){ if (v == 37) { tank.style.left=parseInt(tank.style.left.replace("px",""))-2+"px" console.log("左"); } if (v == 38) { tank.style.top=parseInt(tank.style.top.replace("px",""))-2+"px" console.log("上"); } if (v == 39) { tank.style.left=parseInt(tank.style.left.replace("px",""))+2+"px" console.log("右"); } if (v == 40) { console.log("xia",tank.style.top); tank.style.top=parseInt(tank.style.top.replace("px",""))+2+"px" console.log("下"); } } }) },100) </script>
</body>
</html>
备注
手机上敲的,请谅解这个代码样式,若感兴趣请移步到坦克大战移动小demo
该项目由上下左右方向键控制蓝色块移动