mousemove事件在Javascript中没有像预期的那样工作

时间:2015-11-20 23:11:06

标签: javascript html5 canvas mousemove

我在下面有一些代码用于开始使用HTML5画布制作的蛇游戏。出于某种原因,我暂时用来表示我的蛇的红色圆圈正在不断地沿着鼠标移动的路径绘制。它以食物为起点。在浏览器中查看它,因为它很难描述。我想要的只是圆圈跟随鼠标并留下一条小路,它终止并且不会停留在画布上。我该怎么做呢提前谢谢!

<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Snake 2.0</title>
</head>

<style>

</style>

<body>
    <div>
        <canvas id="canvas" width=500 height=500></canvas>
    </div>

<script type="text/javascript">
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    makeFood();

    function makeFood() {
        foods = [];
        for (var i = 0; i < 1; i++){
            foods.push(new Food());
        }
    }

    function Food() {
        this.x = Math.random() * canvas.width;
        this.y = Math.random() * canvas.height;
        this.radius = 10;

    }

    function drawFood() {
        for (var i = 0; i < 1; i++){
            foods.push(new Food());
        }


        for (var i = 0; i < foods.length; i++){     
            var f = foods[i];
            context.beginPath();

            var grd = context.createRadialGradient(f.x, f.y, (f.radius - (f.radius - 1)), f.x + 1, f.y + 1, (f.radius));
            grd.addColorStop(0, 'red');
            grd.addColorStop(1, 'blue');
            context.arc(f.x, f.y, f.radius, 0, 2 * Math.PI, true);
            context.fillStyle = grd;
            context.fill();

        }
    }

    function makePower() {
        powers = [];
        for (var i = 0; i < 1; i++){
            powers.push(new Power());
        }
    }   

    function Power() {
        this.x = Math.random() * canvas.width;
        this.y = Math.random() * canvas.height;
        this.radius = 8;

    }

    function drawPower() {


        for (var i = 0; i < powers.length; i++){        
            var p = powers[i];
            context.beginPath();

            var grd = context.createRadialGradient(p.x, p.y, (p.radius - (p.radius - 1)), p.x + 1, p.y + 1, (p.radius));
            grd.addColorStop(0, 'green');
            grd.addColorStop(1, 'yellow');
            context.arc(p.x, p.y, p.radius, 0, 2 * Math.PI, true);
            context.fillStyle = grd;
            context.fill();


        }
    }

    canvas.addEventListener("mousemove", function(event) {
        move(event);
        }); 

    function move(e) {
        context.fillStyle = "black";
        context.fillRect(0, 0, canvas.width, canvas.height);    

        var a = e.clientX;
        var b = e.clientY;
        context.arc(a, b, 20, 0, 2 * Math.PI, true);
        context.fillStyle = "red";
        context.fill();
    }



    context.fillStyle = "black";
    context.fillRect(0, 0, canvas.width, canvas.height);    
    var functions = [drawFood];


    var timer = setInterval(function(){
                drawFood();
            }, 5000);


    function stop() {
        clearInterval(timer);
    }


    canvas.addEventListener("click", stop);
    //timer = setInterval(start, 1000);
    //timer = setInterval(start, 5000);
</script>
</body>
</html>

3 个答案:

答案 0 :(得分:0)

您可以先添加“context.beginPath();”在你的“移动”功能中,在“context.arc(a,b,20,0,2 * Math.PI,true);”之前,在我的编辑器中的第102-103行。

function move(e) {
    context.fillStyle = "black";
    context.fillRect(0, 0, canvas.width, canvas.height);

    var a = e.clientX;
    var b = e.clientY;
    context.beginPath();
    context.arc(a, b, 20, 0, 2 * Math.PI, true);
    context.fillStyle = "red";
    context.fill();
}

这是小提琴:http://jsfiddle.net/sd5hh57b/1/

答案 1 :(得分:0)

您应该将您移动的位置存储在一个数组中。然后一个新的计时器应该重新访问这些光盘,并在每次刻度时以更褪色的颜色重绘它们,直到光盘变黑。然后它应该从该数组中删除。

这是fiddle这样做。

代码中的更改从canvas.addEventListener("mousemove",...开始,如下所示:

canvas.addEventListener("mousemove", function(event) {
    // Replaced move function by drawDisc function, 
    // which needs coordinates and color intensity
    drawDisc(event.clientX, event.clientY, 0xF);
}); 

// Array to keep track of previous positions, i.e. the trail
var trail = [];

function drawDisc(x, y, red) {
    context.beginPath();
    context.arc(x, y, 20, 0, 2 * Math.PI, true);
    context.fillStyle = '#' + red.toString(16) + '00000';
    context.fill();
    // If disc is not completely faded out, push it in the trail list
    if (red) {
        trail.push({x: x, y: y, red: red});
    }
}

// New function to regularly redraw the trail
function fadeTrail() {
    var discs = trail.length;
    // If there is only one disc in the trail, leave it as-is, 
    // it represents the current position.
    if (discs > 1) {
        for (var i = discs; i; i--) {
           // take "oldest" disc out of the array:
           disc = trail.shift();
           // and draw it with a more faded color, unless it is
           // the current disc, which keeps its color
           drawDisc(disc.x, disc.y, disc.red - (i === 1 ? 0 : 1));
        }
    }
}
// New timer to fade the trail
var timerFade = setInterval(function(){
    fadeTrail();
}, 10);

我认为评论会明确这是做什么的。请注意,光盘的颜色从0xF00000到0xE00000,0xD00000,...,0x000000。除当前光盘外,该光盘始终保持其0xF00000颜色。

答案 2 :(得分:0)

其他答案是正确的:

  • 在每个新arc()使用beginPath()创建新路径,并避免context.fill()将整体视为单个路径。
  • 使用路径数组存储您的最后位置以绘制路径。

但是,应该避免使用setTimeoutsetInterval(甚至可以避免使用多个)。
现代浏览器支持requestAnimationFrame计时方法,对于olders(基本上是IE9),您可以非常轻松地找到polyfills。它有很多优点,我不会在这里列举,阅读文档。

以下是代码的修改版本,它使用requestAnimationFrame循环。 我还创建了两个屏幕外画布来更新您的foodspowers,这样他们就不会在每次抽奖时消失。两者都将在绘图功能中绘制。

我更改了mousemove处理程序,因此它只更新了跟踪数组,使绘图部分保留在绘制循环中。在每次调用时,它将设置一个moving标志,让我们的绘图函数知道我们正在移动鼠标。否则,它将开始从数组中删除旧的跟踪弧。

    var canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    var context = canvas.getContext("2d");
     // create other contexts (layer like) for your food and powers
    var foodContext = canvas.cloneNode(true).getContext('2d');
    var pwrContext = canvas.cloneNode(true).getContext('2d');

     // a global to tell weither we are moving or not
    var moving;
     // a global to store our animation requests and to allow us to pause it
    var raf;

     // an array to store our trail position
    var trail = [];
     // here we can determine how much of the last position we'll keep at max (can then be updated if we ate some food)
    var trailLength = 10;

     // your array for the foods
    var foods = [];
     // a global to store the last time we drawn the food, no more setInterval
    var lastDrawnFood = 0;


     // start the game
    draw();

    function makeFood() {
      foods.push(new Food());
    }

    function Food() {
      this.x = Math.random() * canvas.width;
      this.y = Math.random() * canvas.height;
      this.radius = 10;

    }

    function drawFood() {
        // clear the food Canvas (this could be done only if we ate some, avoiding the loop through all our foods at each call of this method)
        foodContext.clearRect(0, 0, canvas.width, canvas.height);
        foods.push(new Food());
        for (var i = 0; i < foods.length; i++) {
          var f = foods[i];
          // draw on the food context
          foodContext.beginPath();
          foodContext.arc(f.x, f.y, f.radius, 0, 2 * Math.PI, true);
          var foodGrd = foodContext.createRadialGradient(f.x, f.y, (f.radius - (f.radius - 1)), f.x + 1, f.y + 1, (f.radius));
          foodGrd.addColorStop(0, 'red');
          foodGrd.addColorStop(1, 'blue');
          foodContext.fillStyle = foodGrd;
          foodContext.fill();

        }
      }
      // I'll let you update this one

    function makePower() {
      powers = [];
      for (var i = 0; i < 1; i++) {
        powers.push(new Power());
      }
    }

    function Power() {
      this.x = Math.random() * canvas.width;
      this.y = Math.random() * canvas.height;
      this.radius = 8;

    }

    function drawPower() {
        pwrContext.clearRect(0, 0, canvas.width, canvas.height);
        for (var i = 0; i < powers.length; i++) {
          var p = powers[i];
          var pwrGrd = pwrContext.createRadialGradient(p.x, p.y, (p.radius - (p.radius - 1)), p.x + 1, p.y + 1, (p.radius));
          pwrGrd.addColorStop(0, 'green');
          pwrGrd.addColorStop(1, 'yellow');
          pwrContext.beginPath();

          pwrContext.arc(p.x, p.y, p.radius, 0, 2 * Math.PI, true);
          pwrContext.fillStyle = pwrGrd;
          pwrContext.fill();


        }
      }
      // the event object is already passed, no need for an anonymous function here
    canvas.addEventListener("mousemove", move);

    function move(e) {
      // we paused the game, don't update our position
      if (!raf) return;
      // update the snake
      var a = e.clientX - canvas.offsetLeft;
      var b = e.clientY - canvas.offsetTop;
      trail.splice(0, 0, {
        x: a,
        y: b
      });
      // tell our draw function that we moved
      moving = true;
    }


    function draw(time) {
      // our food timer
      if (time - lastDrawnFood > 5000) {
        lastDrawnFood = time;
        drawFood();
      }

      // clear the canvas
      context.fillStyle = "black";
      context.fillRect(0, 0, canvas.width, canvas.height);
      // draw the food
      context.drawImage(foodContext.canvas, 0, 0);
      // draw the power
      context.drawImage(pwrContext.canvas, 0, 0);
      //draw the snake
      for (var i = 0; i < trail.length; i++) {
        // decrease the opacity
        opacity = 1 - (i / trail.length);
        context.fillStyle = "rgba(255, 0,0," + opacity + ")";
        // don't forget to create a new Path for each circle
        context.beginPath();
        context.arc(trail[i].x, trail[i].y, 20, 0, 2 * Math.PI, true);
        context.fill();
      }
      // if we're not moving or if our trail is too long
      if ((!moving || trail.length > trailLength) && trail.length > 1)
      // remove the oldest trail circle
        trail.pop();

      // we're not moving anymore
      moving = false;
      // update the animation request
      raf = requestAnimationFrame(draw);
    }

    context.fillStyle = "black";
    context.fillRect(0, 0, canvas.width, canvas.height);

    function toggleStop() {
      if (!raf) {
        // restart the animation
        raf = window.requestAnimationFrame(draw);
      } else {
        // cancel the next call
        cancelAnimationFrame(raf);
        raf = 0;
      }
    }


    canvas.addEventListener("click", toggleStop);
html, body{margin:0;}
<canvas id="canvas" width=500 height=500></canvas>