简体   繁体   English

如何让我的HTML画布点更自然地移动?

[英]How can i make my HTML canvas dots move more naturally?

Link to my code pen here 链接到我的代码笔在这里

I would like opinions on how i could make the canvas dots move in a more fluid, liquid like way. 我想知道如何让画布点以更流畅,更液体的方式移动。

I've tried limiting the direction for a certain number of renders (draw()), which has improved it a little! 我已经尝试限制一定数量的渲染(draw())的方向,这已经改善了一点! But it still lacks fluidity, coming across as rigid and 'hard-coded'. 但它仍然缺乏流动性,只是僵硬和“硬编码”。

This switch statement is the way direction is set, either passed a random integer or the previous direction. 此switch语句是方向设置的方式,可以传递随机整数或前一个方向。

 switch (direction) {
                    case 1:
                      star.x--;
                      break;
                    case 2:
                      star.x++;
                      break;
                    case 3:
                      star.y--;
                      break;
                    case 4:
                      star.y++;
                      break;
                    case 5:
                      star.y--;
                      star.x--;
                      break;
                    case 6:
                      star.y--;
                      star.x++;
                      break;
                    case 7:
                      star.y++;
                      star.x++;
                      break;
                    case 8:
                      star.y++;
                      star.x--;
                      break;
}

Thanks! 谢谢!

You can do this by: 你可以这样做:

  • Generating a cardinal spline based on random line points 基于随机线点生成基数样条
  • Walk along that line and plot a star on current position 沿着那条线走,并在当前位置上绘制一颗星

Why cardinal spline? 为什么选择基数样条? A cardinal spline will generate a smooth line between a set of points. 基数样条曲线将在一组点之间生成平滑线。 If also has a tension value. 如果还有张力值。 By exaggerating the tension value (ie outside the normal [0,1] range) it will produce curly lines instead. 通过夸大张力值(即在正常[0,1]范围之外),它将产生卷曲的线条。

快照

// draw example lines
var ctx = c.getContext("2d"), p = [0,100, 25,40, 50,70, 75,50, 100,80, 125,32, 150,100, 175,60];
ctx.font = "bold 16px sans-serif";

render(0); render(0.5); render(-2);
ctx.setTransform(1,0,0,1,0, 110);

render(-2, 3, "Segments: 3"); render(-2, 9, "Segments: 9"); render(-2, 25, "Segments: 25");

function render(t, seg, txt) {
  ctx.beginPath();
  ctx.moveTo(0, 100);
  ctx.curve(p, t, seg || 20);
  ctx.stroke();
  ctx.fillText(txt ? txt : (!t ? "Plain poly-line" : "Cardinal, tension: " + t), 0, 20);
  ctx.translate(200,0);
}

We can take advantage of this property and plot a point along such a line to produce a liquid-ish movement. 我们可以利用这个属性并沿着这样的线绘制一个点以产生液体运动。 The movement can be refined by de/increase the segment resolution between each line in the spline which will affect the smoothness as well as the speed. 可以通过降低/增加样条中每条线之间的分段分辨率来改进运动,这将影响平滑度和速度。

Other advantages is that we don't have to calculate anything in the animation itself (there will be an initial "peak" when setting up the points (cache) though), we just update the array pointer and render. 其他优点是我们不必在动画本身中计算任何东西(在设置点(缓存)时会有一个初始的“峰值”),我们只是更新数组指针并渲染。 And the distribution will be fairly even as the points are forces along somewhat evenly distributed (invisible) paths. 并且分布将是相当均匀的,因为点是沿着稍微均匀分布(不可见)路径的力。

How to implement it can vary of course - here is one example of an approach: 如何实现它可以改变当然 - 这是一个方法的一个例子:

Example implementation 示例实现

Define a star object (it should really be prototyped but for the sake of demo): 定义一个星形对象(它应该是原型,但为了演示):

function Star(ctx, xseg) {

    var points = [],              // holds points for cardinal points
        cPos = 0, oPos = -1,      // positions in line
        len,
        w = ctx.canvas.width,
        x = -10, y = -10;

    // this iterates and loop the point list            
    this.animate = function() {
        cPos++;

        if (cPos > len - 2) {
            cPos = 0; oPos = -1;
        }

        var pos = cPos * 2;
        x = points[pos];
        y = points[pos + 1];

        drawStar();
    }

    // render some star
    function drawStar() {
        ctx.rect(x, y, 2, 2);
    }

    // This generate a set of random points, then converts those into
    // points for a cardinal spline (linked as script).
    function generatePath() {
        var w = ctx.canvas.width,
            h = ctx.canvas.height,
            numOfSeg = 20,
            dh = h / numOfSeg,
            i= 0, l, x, y;

        for(; i<= numOfSeg; i++) {          
            x = xseg + w / 8 * Math.random();
            y = h - (i * dh + ((dh / 2) * Math.random() - (dh / 4)));
            points.push(x, y);
        }

        points = curve(points, -2, 200 * Math.random() + 100);
        l = points.length;

        // adjust for out of edges
        for(i = 0; i < l; i += 2) if (points[i] > w) points[i] -= w;
        len = points.length / 2;
        cPos = parseInt(len * Math.random());
    }   
    generatePath();
}

Full example 完整的例子

function Star(ctx, xseg) {

  var points = [],              // holds points for cardinal points
      cPos = 0, oPos = -1,      // positions in line
      len,
      w = ctx.canvas.width,
      x = -10, y = -10;

  this.animate = function() {
    cPos++;
    if (cPos > len - 2) {
      cPos = 0;  oPos = -1;
    }

    var pos = cPos * 2;
    x = points[pos];
    y = points[pos + 1];

    drawStar();
  };

  function drawStar() {
    ctx.moveTo(x + 2, y);
    ctx.arc(x, y, 2, 0, Math.PI*2);
  }

  function generatePath() {
    var w = ctx.canvas.width,
        h = ctx.canvas.height,
        numOfSeg = 20,
        dh = h / numOfSeg,
        i= 0, l, x, y;

    for(; i <= numOfSeg; i++) {         
      x = xseg + w / 8 * Math.random();
      y = h - (i * dh + ((dh / 2) * Math.random() - (dh / 4)));
      points.push(x, y);
    }

    points = getCurvePoints(points, -2, (400 * Math.random() + 200)|0);
    l = points.length;

    for(i = 0; i < l; i += 2) if (points[i] > w) points[i] -= w;
    len = points.length / 2;
    cPos = (len * Math.random())|0;

  }
  generatePath();
}

// Main code
var canvas = document.querySelector("canvas"),
    ctx = canvas.getContext("2d"),
    stars = [],
    numOfStars = 100,
    segs = canvas.width / numOfStars, 
    i = 0,
    throttle = 0,
    delay = 2;

// create stars
for(; i < numOfStars; i++) stars.push(new Star(ctx, i * segs - segs));

ctx.fillStyle = "#fff";
ctx.shadowColor ="#fff";
ctx.shadowBlur = 7;

// ANIMATE
(function animate() {      
  if (!throttle) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    for(var i = 0; i < stars.length; i++) stars[i].animate();
    ctx.fill(); 
  }

  throttle++;
  if (throttle === delay) throttle = 0;

  requestAnimationFrame(animate);
})();

See code for cardinal spline implementation in this answer . 请参阅此答案中的基数样条实现的代码。

Another approach is to use particles and variate the velocity using for example a sinus function. 另一种方法是使用粒子并使用例如正弦函数来变化速度。 For this to work optimally you may need a velocity grid instead to affect a particle based on location. 为了使其最佳地工作,您可能需要使用速度网格来影响基于位置的粒子。 The grid can have random directions and velocities. 网格可以具有随机方向和速度。

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

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