2015-11-20 8 views
0

У меня есть код ниже для начала игры змеи, которую я делаю с помощью холста HTML5. По какой-то причине красный круг, который я временно использую для представления своей змеи, постоянно рисует путь, по которому движется мышь, и использует пищу в качестве отправной точки. Проверьте это в своем браузере, потому что это очень сложно описать. Все, что я хочу, - это круг, чтобы следовать за мышью и оставить небольшой след, который заканчивается и не остается на холсте. Как я буду заниматься этим. Заранее спасибо!Событие mousemove не работает, как ожидалось в Javascript

<!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> 
+0

A [скрипку] (HTTP: // jsfiddle.net/sd5hh57b /) кода OP. – Teemu

+0

Удивительно, спасибо за это! –

ответ

0

Вы можете начать с добавления "context.beginPath();" в вашей функции «move», перед «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/

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.

0

Другие ответы правы:

  • Использование beginPath() на каждом новом arc(), чтобы создать новый путь и избежать context.fill() рассматривает весь как единый путь.
  • Используйте трейляр Array, чтобы сохранить ваши последние позиции, чтобы нарисовать тропу.

Но использование setTimeout и setInterval следует избегать (и даже далее использование нескольких из них).
Современные браузеры поддерживают requestAnimationFrame метод синхронизации, а для пожилых людей (в основном IE9) вы можете легко найти polyfills. У него есть много преимуществ, которые я не буду перечислять здесь, прочитав документы.

Здесь представлена ​​измененная версия вашего кода, в которой используется цикл requestAnimationFrame. Я также создал два заставных холста, чтобы обновить ваши foods и powers, таким образом они не исчезнут в каждой ничьей. Оба будут раскрашены в функцию рисования.

Я изменил обработчик 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>