首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HTML5画布javascript雨动画(如何高效简单的实现!)

问HTML5画布javascript雨动画(如何高效简单的实现!)
EN

Stack Overflow用户
提问于 2012-05-30 11:22:32
回答 2查看 9.9K关注 0票数 9

我在canvas中尝试了这两种方法,但都没有显示,而且我怀疑它是否有效:/。我试着让雨从屏幕上落下来..想知道做这件事最有效的方法是什么。我是一个动画的初学者,真的很感谢帮助。

我怀疑创建一个雨对象会是最好的,每个对象的质量都是从屏幕上下来,然后到达顶部,然后是一个带有随机x值的them...maybe数组,其中的画布宽度和y值为0,但我不知道如何实现它。请帮帮我!

代码语言:javascript
复制
                xofRain = 20;
        startY = 0;
        ctx.beginPath();
        ctx.moveTo(xofRain, startY);
        ctx.lineTo(xofRain, startY + 20);
        ctx.closePath();
        ctx.fillStyle = "black"; 
        ctx.fill();


     function rain(xofRain){

        startY = canvas.height();

        ctx.moveTo(xofRain, startY);
        ctx.beginPath();
        ctx.lineTo(xofRain, startY + 3);
        ctx.closePath();
        ctx.fillStyle = "blue"; 
        ctx.fill();
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-30 14:10:31

这就是你的答案,这个雪雨是用纯HTML5画布创建的,用来实现这个动画的技术被称为“双缓冲动画”。首先,知道什么是双缓冲动画技术是很好的。

双缓冲技术:这是一种先进的技术,使动画清晰,其中闪烁较少。在该技术中,使用了2个画布,其中一个画布用于在网页上显示结果,另一个画布用于在后台过程中创建动画屏幕。

这将如何帮助完整,假设我们必须创建一个非常高的移动次数的动画,就像在我们的雪花坠落示例中,有许多雪花正在以自己的速度移动,所以让它们保持移动,我们必须改变每个雪花的位置并在画布上更新它,这是一个相当繁重的过程。

因此,现在我们不是直接在页面画布上更新每个Flake,而是创建一个缓冲区画布,所有这些更改都会在其中发生,我们只需在30ms后从缓冲区画布中捕获一张图片,并将其显示在真正的画布上。

这样我们的动画将是清晰的,没有闪烁。所以这里有一个活生生的例子。

http://aspspider.info/erishaan8/html5rain/

下面是它的代码:

​

代码语言:javascript
复制
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset=utf-8 />
    <title>HTML5 Rain</title>
    <!--[if IE]>
      <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <style>
      article, aside, figure, footer, header, hgroup, 
      menu, nav, section { display: block; }
    </style>
    <script type="text/javascript">
        var canvas = null;
        var context = null;
        var bufferCanvas = null;
        var bufferCanvasCtx = null;
        var flakeArray = [];
        var flakeTimer = null;
        var maxFlakes = 200; // Here you may set max flackes to be created 
    
        function init() {
            //Canvas on Page
            canvas = document.getElementById('canvasRain');
            context = canvas.getContext("2d");
            //Buffer Canvas
            bufferCanvas = document.createElement("canvas");
            bufferCanvasCtx = bufferCanvas.getContext("2d");
            bufferCanvasCtx.canvas.width = context.canvas.width;
            bufferCanvasCtx.canvas.height = context.canvas.height;
    
            
            flakeTimer = setInterval(addFlake, 200);
    
            Draw();
    
            setInterval(animate, 30);
             
        }
        function animate() {
            
            Update();
            Draw();
            
        }
        function addFlake() {
    
            flakeArray[flakeArray.length] = new Flake();
            if (flakeArray.length == maxFlakes)
                clearInterval(flakeTimer);
        }
        function blank() {
            bufferCanvasCtx.fillStyle = "rgba(0,0,0,0.8)";
            bufferCanvasCtx.fillRect(0, 0, bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);
            
        }
        function Update() {
            for (var i = 0; i < flakeArray.length; i++) {
                if (flakeArray[i].y < context.canvas.height) {
                    flakeArray[i].y += flakeArray[i].speed;
                    if (flakeArray[i].y > context.canvas.height)
                        flakeArray[i].y = -5;
                    flakeArray[i].x += flakeArray[i].drift;
                    if (flakeArray[i].x > context.canvas.width)
                        flakeArray[i].x = 0;
                }
            }
            
        }
        function Flake() {
            this.x = Math.round(Math.random() * context.canvas.width);
            this.y = -10;
            this.drift = Math.random();
            this.speed = Math.round(Math.random() * 5) + 1;
            this.width = (Math.random() * 3) + 2;
            this.height = this.width;
        }
        function Draw() {
            context.save();
            
            blank();
    
            for (var i = 0; i < flakeArray.length; i++) {
                bufferCanvasCtx.fillStyle = "white";
                bufferCanvasCtx.fillRect(flakeArray[i].x, flakeArray[i].y, flakeArray[i].width, flakeArray[i].height);
            }
    
            
            context.drawImage(bufferCanvas, 0, 0, bufferCanvas.width, bufferCanvas.height);
            context.restore();
        }
      
    </script>
    </head>
    <body onload="init()">
      <canvas  id="canvasRain" width="800px" height="800px">Canvas Not Supported</canvas>
    </body>
    </html>

​

同样,如果你发现这个帮助是完整的,接受它作为答案,然后编造出来。o_O

干杯!

票数 16
EN

Stack Overflow用户

发布于 2017-07-20 18:54:57

我不确定什么是“最有效”。如果是我的话,我会用WebGL来做,但我不清楚这是否有效。

在这两种情况下,我都会尝试使用无状态公式。可以说,为每个雨滴创建和更新状态的速度很慢。

​

代码语言:javascript
复制
const ctx = document.querySelector("canvas").getContext("2d");
const numRain = 200;

function render(time) {
  time *= 0.001;  // convert to seconds
  
  resizeCanvasToDisplaySize(ctx.canvas);
  
  const width = ctx.canvas.width;
  const height = ctx.canvas.height;
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, width, height);  
  
  resetPseudoRandom();
  
  const speed = time * 500;
  ctx.fillStyle = "#68F";
  for (let i = 0; i < numRain; ++i) {
    const x = pseudoRandomInt(width);
    const y = (pseudoRandomInt(height) + speed) % height;
    ctx.fillRect(x, y, 3, 8);
  }
  
  requestAnimationFrame(render);
}

requestAnimationFrame(render);

let randomSeed_ = 0;
const RANDOM_RANGE_ = Math.pow(2, 32);

function pseudoRandom() {
  return (randomSeed_ =
          (134775813 * randomSeed_ + 1) %
          RANDOM_RANGE_) / RANDOM_RANGE_;
};

function resetPseudoRandom() {
  randomSeed_ = 0;
};

function pseudoRandomInt(n) {
  return pseudoRandom() * n | 0;
}

function resizeCanvasToDisplaySize(canvas) {
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    canvas.width = width;
    canvas.height = height;
  }
}
代码语言:javascript
复制
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
代码语言:javascript
复制
<canvas></canvas>

​

请注意,我可以对每一行使用ctx.moveTo(x, y); ctx.lineTo(x, y + 8);,然后在名为ctx.stroke()的循环末尾使用它。我没有这样做,因为我认为它的效率会低于使用ctx.fillRect。为了让画布绘制线条,它实际上必须分配一个动态路径(您称为ctx.beginPath)。然后,它必须记录您添加的所有行。然后,它必须将这些线扩展为各种类型的顶点,以栅格化这些线。你基本上可以使用see the various algorithms it uses here。相反,这一切都不一定会发生在ctx.fillRect上。没有分配必须发生(并不是说它们不发生,只是说它们不需要发生)。画布可以只使用一个预先分配的四边形,并通过传递正确的矩阵在GPU上绘制它,以绘制您要求的任何矩形。当然,调用ctx.fillRect 200次可能比调用ctx.moveTo、ctx.lineTo 200s + ctx.stroke一次开销更大,但这实际上是由浏览器决定的。

上面的雨可能是也可能不是足够好的降雨效果。这真的不是我发帖的重点。重点是效率。几乎所有具有某种雨效果的游戏都会为它们的雨做某种无状态的公式。不同的公式将产生不同的或更少的重复降雨。关键是它是无状态的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10809599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档