简体   繁体   English

画布:按下键时出现奇怪的行为

[英]Canvas: Strange behavior when pressing key down

By default the rectangle of my canvas should move from left to right. 默认情况下,我的画布矩形应从左向右移动。 When pressing the key down, it should start moving down. 当按下键时,它应该开始向下移动。

 var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), x = 0, y = 0; function draw(x_move, y_move) { requestAnimationFrame(function() { draw(x_move, y_move); }); ctx.beginPath(); ctx.rect(x, y, 20, 20); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#ffffff"; ctx.fill(); ctx.closePath(); x = x + x_move; y = y + y_move; } draw(1, 0); document.addEventListener('keydown', function(event) { //console.log(event.keyCode); if (event.keyCode == 40) { draw(0, 1); } }); 
 canvas { background-color: red; } 
 <canvas id="canvas" width="600" height="400"></canvas> 

Using the code above, you may at least notice two issues: 使用上面的代码,您至少可以注意到两个问题:

  1. When pressing key down, the rectangle moves down but also keeps moving to the right. 按下键时,矩形向下移动但仍向右移动。
  2. When you keep pressing the down key multiple times, the speed gets increased. 当您多次按下向下键时,速度会增加。

How can I fix those issues? 我该如何解决这些问题?

See where you call 看看你打电话的地方

requestAnimationFrame(function() {
    draw(x_move, y_move);
  });

You're now recursively calling draw() . 你现在递归调用draw()

Now every time you call draw() , it gets called over and over and over again. 现在每次调用draw() ,都会一遍又一遍地调用它。 And when you call it from the keydown event, you call it 2x as often, then 3x as often on the second time you press it, etc. 当你从keydown事件中调用它时,你会经常调用它2倍,然后在第二次按下它时经常调用3倍,等等。

I'm not entirely clear on what your objective is here, but if you wanted to just adjust the trajectory of the square by pressing down, you could do something like this: 我不太清楚你的目标是什么,但如果你想通过按下来调整方块的轨迹,你可以这样做:

document.addEventListener('keydown', function(event) {
  //console.log(event.keyCode); 
  if (event.keyCode == 40) {
    adjustDownwardTrajectory();
  }
});

and have that adjustDownwardTrajectory() change some downwardTrajectory variable such that: 并使adjustDownwardTrajectory()改变一些向下的adjustDownwardTrajectory()变量,使得:

function draw(x_move, y_move) { 
  requestAnimationFrame(function() {
    draw(x_move, y_move);
  }); 
  ctx.beginPath();
  ctx.rect(x, y, 20, 20);
  ctx.clearRect(0, 0, canvas.width, canvas.height); 
  ctx.fillStyle = "#ffffff";
  ctx.fill();
  ctx.closePath();
  x = x + x_move;
  y = y + y_move + downwardTrajectory;
} 

I believe this is what you want to be doing (and you were close!). 我相信这就是你想做的事情(你很亲密!)。 I hope this is the behaviour you were looking for. 我希望这是你正在寻找的行为。

A related point : It may be a good idea to wrap x_move and y_move up in a closure with these functions so you avoid accidentally changing them in other parts of the program. 一个相关的观点 :将x_movey_move在具有这些函数的闭包中可能是个好主意,这样可以避免在程序的其他部分中意外地更改它们。 That way the functions you implement for changing directions of the square will have private access to these variables. 这样,您实现的用于更改方形方向的函数将具有对这些变量的私有访问权限。

 var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), x = 0, y = 0; var x_move = 1; var y_move = 0; function draw() { requestAnimationFrame(function() { draw(); }); ctx.beginPath(); ctx.rect(x, y, 20, 20); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#ffffff"; ctx.fill(); ctx.closePath(); x = x + x_move; y = y + y_move; } draw(); document.addEventListener('keydown', function(event) { //console.log(event.keyCode); if (event.keyCode == 40) { x_move = 0; y_move = 1; } }); 
 canvas { background-color: red; } 
 <canvas id="canvas" width="600" height="400"></canvas> 

keyboardEvent.keyCode is a depreciated property. keyboardEvent.keyCode是折旧属性。 You should use keyboardEvent.code or keyboardEvent.key they provided a named key which is much easier to manage than trying to remember key codes. 您应该使用keyboardEvent.codekeyboardEvent.key它们提供了一个命名键,它比试图记住键代码更容易管理。

You can use fillRect rather than rect and you don't need to use beginPath and fill . 您可以使用fillRect而不是rect ,您不需要使用beginPathfill You don't need to use closePath you only use it if you want to close a shape (ie add a line from the last point to the first) rect is already closed 您不需要使用closePath ,只有在想要关闭形状时才使用它(即从最后一个点到第一个点添加一条线) rect已经关闭

You can set the callback directly as the argument for requestAnimationFrame 您可以直接将回调设置为requestAnimationFrame的参数

It pays to group related data together. 将相关数据分组在一起是值得的。 In this case the square has a position x , y and a delta position ( x_move , y_move ) that are better off in a object. 在这种情况下,正方形具有位置xy和在对象中更好地关闭的增量位置( x_movey_move )。 A good clue that you have related data is when you find yourself adding the same name to a set of variables. 您有相关数据的好线索是当您发现自己为一组变量添加相同的名称时。 Objects can also include behaviour in the form of functions like draw and update 对象还可以包括drawupdate等功能形式的行为

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// list of named keys to record state of
const keys = {
   ArrowDown: false,
};
// create key event listeners
document.addEventListener('keydown', keyEvent);
document.addEventListener('keyup', keyEvent);

// define the square
const square = {
    x : 0,  // position
    y : 0,
    dx : 0, // delta pos
    dy : 0,
    draw () {  // function to render the square
        ctx.fillStyle = "#ffffff";
        ctx.fillRect(this.x, this.y, 20, 20);
    },
    update () { // function to update square
        if(keys.ArrowDown){
            this.dx = 0;
            this.dy = 1;
        }else {
            this.dx = 1;
            this.dy = 0;
        }
        this.x += this.dx;
        this.y += this.dy;
    }
}

// main animation update function called once per frame 1/60th second
function update () {
  requestAnimationFrame(update);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  square.update();
  square.draw();
}

// key event records named key state (false up, true down)
function keyEvent (event) {
   if(keys[event.code] !== undefined){
      keys[event.code] = event.type === "keydown";
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM