JavaScriptで雪を降らせてみた

プログラミング

あけましておめでとうございます。本年もよろしくお願いいたします。

絵心がなくうまく絵が描けないので、JavaScriptで絵を描いて見ることにしました。今回はほとんど解説なしです。

画面上で雪を降らせてみた

実際の雪の動きには近くないのですが、揺れながら降ってくる様子を出してみました。下のリンクから実際に動くページがみられると思います。ちなみに放置すると、雪が積もってしまいます。

雪を降らせてみた

雪を降らせるプログラム

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Snow man</title>
    <style>
      #canvas {
        background: #000;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" width="640" height="480"></canvas>
    <form id="form">
      雪の数:<span id="countOfSnow">500</span>
      <input type="button" value="↓" onclick="snow(-10)">
      <input type="button" value="↑" onclick="snow(+10)"> <br />

      風:<span id="windSpeed">0</span>
      <input type="button" value="←" onclick="wind(-1)">
      <input type="button" value="→" onclick="wind(+1)">
    </form>

    <script>
      var canvas = document.getElementById('canvas');
      var ctx = canvas.getContext('2d');
      var canvasWidth = canvas.width;
      var canvasHeight = canvas.height;

      var itvEvt;
      var fps = 60;
      
      var snowCount;
      var arrayImage = [];
      var maxSnow = 1000;
      var fallSnow = 0;

      var windSpeed;
      var maxWind = 20;

      init();

      function init(){
        snowCount = parseInt(
          document.getElementById('countOfSnow').textContent);
        windSpeed = parseInt(
          document.getElementById('windSpeed').textContent);

        for( var i=0; i<snowCount; i++ ){
          arrayImage.push({
            "x" : Math.random() * canvasWidth,
            "y" : Math.random() * canvasHeight,
          });
        }
        clearInterval( itvEvt );
        itvEvt = setInterval( draw, 1000/fps );
      }

      function draw(){
        ctx.clearRect( 0, 0, canvasWidth, canvasHeight );
        drawSnowman();
        ctx.fillStyle = 'rgb( 255, 255, 255 )';
        ctx.fillRect( 0, canvasHeight-fallSnow/100, canvasWidth, fallSnow/100 );
        drawSnow();
      }

      function drawSnow() {
        ctx.fillStyle = 'rgb( 255, 255, 255 )';
        for( var i=0; i<snowCount; i++ ){
          arrayImage[i].x += Math.random()*2 -1 +windSpeed;
          arrayImage[i].y += Math.random()*1.5;

          arrayImage[i].x = ( arrayImage[i].x +canvasWidth ) % canvasWidth;

          if( arrayImage[i].y > canvasHeight ){
            arrayImage[i].x = Math.random() * canvasWidth;
            arrayImage[i].y = -3;
            fallSnow++;
          }

          ctx.beginPath();
          ctx.arc( arrayImage[i].x, arrayImage[i].y, 3, 0, 2*Math.PI, false );
          ctx.fill();
        }
      }

      function drawSnowman(){
        ctx.beginPath();
        ctx.fillStyle = 'rgb( 255, 255, 255)';
        ctx.arc( 500, 350, 50, 0, 2*Math.PI, false ); //頭
        ctx.arc( 500, 440, 70, 0, 2*Math.PI, false ); //胴
        ctx.fill();

        ctx.beginPath();
        ctx.fillStyle = 'rgb( 231, 126, 49 )';
        ctx.arc( 500, 350, 7, 7, 0, 2*Math.PI, false );//鼻
        ctx.fill();

        ctx.beginPath();
        ctx.lineWidth = 3;
        ctx.strokeStyle = 'rgb( 0, 0, 0 )';
        ctx.arc( 485, 335, 5 , 0, Math.PI, true );    //左目
        ctx.stroke();

        ctx.beginPath();
        ctx.strokeStyle = 'rgb( 0, 0, 0 )';
        ctx.arc( 515, 335, 5 , 0, Math.PI, true );    //右目
        ctx.stroke();

        ctx.beginPath();
        ctx.lineWidth = 5;
        ctx.strokeStyle = 'rgb( 255, 0, 0 )';         //口
        ctx.arc( 500, 350, 25 , 45*Math.PI/180, 135*Math.PI/180, false );
        ctx.stroke();

        ctx.translate( 500, 350 );
        ctx.rotate( 15 * Math.PI/180 );
        ctx.fillStyle = 'rgb( 0, 0, 255 )';
        ctx.fillRect( -30, -57, 60, 14 );   //バケツのふち
        ctx.fillRect( -20, -87, 40, 30 );   //バケツ本体
        ctx.rotate( -15 * Math.PI/180 );
        ctx.translate( -500, -350 );
      }

      function snow( num ){
        if( 0<=snowCount+num && snowCount+num<=maxSnow ){
          snowCount += num;
          document.getElementById('countOfSnow').innerHTML = snowCount;
          init();
        }
      }

      function wind( num ){
        if( -maxWind<=windSpeed+num && windSpeed+num<=maxWind ){
          windSpeed += num;
          document.getElementById('windSpeed').innerHTML = windSpeed;
          init();
        }
      }

    </script>
  </body>
</html>

長いように見えるけれど、87~123行目で雪だるまを描いていて、これが36行もあるのが原因のような気がします。

今回はこれでおしまいにします。それでは、また。

Posted by 春日井 優