javascript - Canvas 动画,我的 JavaScript 代码中的数学计算问题

标签 javascript algorithm canvas javascript-objects

想法:

嗨,这是我第一次尝试 Canvas 动画。我不确定这个概念是否已经存在,但我将我的版本称为“双态动画”。这个想法是这样的:为屏幕上的每个对象创建一个 map ,其中包含三个子 map 。其中一个子图保存当前状态属性(动画对象的),第二个保存最终目的地(动画对象的),第三个用于分割增量以确保对象(屏幕上)到达其最终目的地在`framesForChange 中设置的帧数。

问题:

请注意,随着动画的进行,对象逐渐向下推到右下角,但 x 和 y 轴的数字继续增长。我知道我正在生成随机数以将其限制在视口(viewport)的宽度 (x) 和高度 (y) 内。为什么会这样?我该如何解决?

代码:

如果您对我如何提高效率有任何建议(或者,更重要的是,解决 [上述] 问题),请在您的回答或评论中提及。谢谢。

window.addEventListener('load', initializeCanvasTwo());

function initializeCanvasTwo() {
  var canvas, c, map = {},
    framesForChange = 360;

  initializeCanvas();
  resizeCanvas();
  initializeMapping();
  draw();

  window.addEventListener('resize', function() {
    resizeCanvas();
  });

  function initializeCanvas() {
    canvas = document.getElementById('canvasTwo');
    c = canvas.getContext('2d');
  }

  function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    c.width = window.innerWidth;
    c.height = window.innerHeight;
  }

  function initializeMapping() {
    var n = Math.floor(window.innerWidth * window.innerHeight / 20000);
    for (var i = 0; i < n; i++) {
      map[i] = {
        current: {
          startX: getRandomX(),
          startY: getRandomY(),
          endX: getRandomX(),
          endY: getRandomY()
        },
        final: {
          startX: getRandomX(),
          startY: getRandomY(),
          endX: getRandomX(),
          endY: getRandomY()
        },
        increment: {

        }
      };
      map[i].increment.startXIncrement = (map[i].final.startX - map[i].current.startX) / framesForChange;
      map[i].increment.startYIncrement = (map[i].final.startY - map[i].current.startY) / framesForChange;
      map[i].increment.endXIncrement = (map[i].final.endX - map[i].current.endX) / framesForChange;
      map[i].increment.endYIncrement = (map[i].final.endY - map[i].current.endY) / framesForChange;
    }
  }

  function getRandomX() {
    return Math.floor(Math.random() * window.innerWidth);
  }

  function getRandomY() {
    return Math.floor(Math.random() * window.innerHeight);
  }

  function updateMap() {
    var n = Object.keys(map).length;
    for (var i = 0; i < n; i++) {
      if (map[i].final.startX - map[i].current.startX < map[i].increment.startXIncrement) {
        //startX transition complete: set new destination...
        map[i].final.startX = getRandomX();
        map[i].increment.startXIncrement = (map[i].final.startX - map[i].current.startX) / framesForChange;
      } else {
        map[i].current.startX += map[i].increment.startXIncrement;
      }

      if (map[i].final.startY - map[i].current.startY < map[i].increment.startYIncrement) {
        //startY transition complete: set new destination...
        map[i].final.startY = getRandomY();
        map[i].increment.startYIncrement = (map[i].final.startY - map[i].current.startY) / framesForChange;
      } else {
        map[i].current.startY += map[i].increment.startYIncrement;
      }

      if (map[i].final.endX - map[i].current.endX < map[i].increment.endXIncrement) {
        //endX transition complete: set new destination...
        map[i].final.endX = getRandomX();
        map[i].increment.endXIncrement = (map[i].final.endX - map[i].current.endX) / framesForChange;
      } else {
        map[i].current.endX += map[i].increment.endXIncrement;
      }

      if (map[i].final.endY - map[i].current.endY < map[i].increment.endYIncrement) {
        //endY transition complete: set new destination...
        map[i].final.endY = getRandomY();
        map[i].increment.endYIncrement = (map[i].final.endY - map[i].current.endY) / framesForChange;
      } else {
        map[i].current.endY += map[i].increment.endYIncrement;
      }
    }
  }

  function draw() {
    c.clearRect(0, 0, window.innerWidth, window.innerHeight);
    c.strokeStyle = 'blue';
    var n = Object.keys(map).length;
    for (var i = 0; i < n; i++) {
      c.beginPath();
      c.moveTo(map[i].current.startX, map[i].current.startY);
      c.lineTo(map[i].current.endX, map[i].current.endY);
      c.stroke();
      c.closePath();
    }
    updateMap();
    requestAnimationFrame(draw);
  }
}
html,
body {
  margin: 0;
  padding: 0;
}
canvas {
  width: 100%;
  height: 100%;
  margin-bottom: -4px;
}
<canvas id="canvasTwo"></canvas>

最佳答案

主要问题在于 if 条件。

您检查最终电流是否小于增量。但是,当 x 试图向左移动或 y 向上移动时(这意味着开始 > 最终),您就会为它们创建新的值。所以只允许去右边和底部。 (要解决此问题,您应该在 if 的两边使用 Math.abs,但这会进一步降低性能)

作为轻微的改进,您应该为 map 使用一个数组,并且由于所有元素都采用相同的帧来完成它们的动画,因此您不应该检查每个点是否已到达其目的地,而是计算帧和一次更新结束位置。

window.addEventListener('load', initializeCanvasTwo());

function initializeCanvasTwo() {
  var canvas, c, map = [],
    framesForChange = 360,
    currentFrame = 360;

  initializeCanvas();
  resizeCanvas();
  initializeMapping();
  draw();

  window.addEventListener('resize', function() {
    resizeCanvas();
  });

  function initializeCanvas() {
    canvas = document.getElementById('canvasTwo');
    c = canvas.getContext('2d');
  }

  function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    c.width = window.innerWidth;
    c.height = window.innerHeight;
  }

  function initializeMapping() {
    var n = Math.floor(window.innerWidth * window.innerHeight / 20000);
    for (var i = 0; i < n; i++) {
      map[i] = {
        current: {
          startX: getRandomX(),
          startY: getRandomY(),
          endX: getRandomX(),
          endY: getRandomY()
        },
        final: {
          startX: getRandomX(),
          startY: getRandomY(),
          endX: getRandomX(),
          endY: getRandomY()
        },
        increment: {

        }
      };
      map[i].increment.startXIncrement = (map[i].final.startX - map[i].current.startX) / framesForChange;
      map[i].increment.startYIncrement = (map[i].final.startY - map[i].current.startY) / framesForChange;
      map[i].increment.endXIncrement = (map[i].final.endX - map[i].current.endX) / framesForChange;
      map[i].increment.endYIncrement = (map[i].final.endY - map[i].current.endY) / framesForChange;
    }
  }

  function getRandomX() {
    return Math.floor(Math.random() * window.innerWidth);
  }

  function getRandomY() {
    return Math.floor(Math.random() * window.innerHeight);
  }

  function updateMap() {
    var n = map.length;
    currentFrame = --currentFrame || framesForChange;
    if (currentFrame == framesForChange){
      // create new values
      for (var i = 0; i < n; i++) {
        map[i].final.startX = getRandomX();
        map[i].final.startY = getRandomY();
        map[i].final.endX = getRandomX();
        map[i].final.endY = getRandomY();
        
        map[i].increment.startXIncrement = (map[i].final.startX - map[i].current.startX) / framesForChange;
        map[i].increment.startYIncrement = (map[i].final.startY - map[i].current.startY) / framesForChange;
        map[i].increment.endXIncrement = (map[i].final.endX - map[i].current.endX) / framesForChange;
        map[i].increment.endYIncrement = (map[i].final.endY - map[i].current.endY) / framesForChange;
      }
    }
    for (var i = 0; i < n; i++) {
        map[i].current.startX += map[i].increment.startXIncrement;
        map[i].current.startY += map[i].increment.startYIncrement;
        map[i].current.endX += map[i].increment.endXIncrement;
        map[i].current.endY += map[i].increment.endYIncrement;
    }
  }

  function draw() {
    c.clearRect(0, 0, window.innerWidth, window.innerHeight);
    
    var n = map.length;
    c.strokeStyle = 'blue';
    for (var i = 0; i < n; i++) {
      c.beginPath();
      c.moveTo(map[i].current.startX, map[i].current.startY);
      c.lineTo(map[i].current.endX, map[i].current.endY);
      c.stroke();
      c.closePath();
    }
    updateMap();
    requestAnimationFrame(draw);
  }
}
html,
body {
  margin: 0;
  padding: 0;
}
canvas {
  width: 100%;
  height: 100%;
  margin-bottom: -4px;
}
<canvas id="canvasTwo"></canvas>

关于javascript - Canvas 动画,我的 JavaScript 代码中的数学计算问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40274835/

相关文章:

javascript - 在由 innerHTML 生成的标签上触发 jQuery 事件

R gbm 为什么 fit$trees 的长度总是数据集 iris 的 n.trees 的 3 倍

android - 在图像中绘制文本时换行

javascript - 异常 float 参数不是有限 Canvas

javascript - PIXI - 禁用 preventDefault 触摸事件在 Android 设备上不起作用

javascript - 当响应仍在返回时,如何逐个对象读取大型 SOLR 响应

javascript - 链接reduce() 和map() Javascript

javascript - JS中螺旋存储像素的算法是什么?

algorithm - 查找文本文件中多行的重复

javascript - 如何检测{{#each pages}}中的页面是否为当前页面?