2013年12月13日金曜日

Canvasを使って雪を降らせよう!

おそようございます.M1のyuuです.
1週間ぶり,2回目の登場です.

今日は13日の金曜日ですね.そろそろホッケーマスクを付けた大男がウォーミング・アップを始めた頃でしょうか.

今回はCanvasを使って"雪"を降らせたいと思います.完成イメージはこちらです.(宣伝じゃないよ)
簡易的にuserAgentを見ているので,スマホ等の携帯端末では表示されません.ご注意下さい.


では,いつもどおりのhtmlから

canvasタグではwidthとheightの指定をstyleとは別に行う必要があります.(指定しない場合width="300",height="150"が初期値として指定されます)
attributeのwidthとheightは描画領域のサイズ指定で,styleのwidthとheightは表示サイズ指定です.

例えば


とすると,拡大率50%で表示されることになります.


これだと等倍になります.styleを指定しない場合は等倍で表示されます.
ここがまず最初にcanvasタグで躓くところだと思います.

で,今回の場合なのですが

「画面全体に表示したいけど,styleで表示サイズを変化させると縮尺変わっちゃうし,でも描画領域を広げすぎると良くないし...」と悩んだ結果です.
描画領域をたくさん確保してもJavaScriptで表示外領域に描画しなきゃ大丈夫だろうという考えのもとこうなりました.
もっと上手い方法があったら教えてください.

次に,JavaScriptです.

(function(){
    var AMOUNT_OF_SNOWFALL = 20; // 降雪量
    var canvas, context;

    document.addEventListener('DOMContentLoaded', initDecoration, false);

    var initDecoration = function(){
        canvas = document.querySelector('#decoration-canvas');
        context = canvas.getContext('2d');
        // 初期設定
        var snowPositions = [];
        for(var i = 0; i < AMOUNT_OF_SNOWFALL; i++){
            var rand = Math.floor(Math.random() * AMOUNT_OF_SNOWFALL);

            snowPositions.push({
                x: (canvas.width / AMOUNT_OF_SNOWFALL) * i,
                y: ((window.innerHeight / AMOUNT_OF_SNOWFALL) * rand) - window.innerHeight * 0.8
            });
        }
 
        updateCanvas(snowPositions);
    };

    var updateCanvas = function(snowPositions){
        setTimeout(function() {
            context.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
            for(var i in snowPositions){
                // y座標調整
                if (snowPositions[i].y > window.innerHeight + 5){
                    snowPositions[i].y = 0;
                }else{
                    snowPositions[i].y += (Math.floor(Math.random() * 20) + 1);
                }
                // x座標調整
                if (snowPositions[i].x > window.innerWidth + 5){
                    snowPositions[i].x = 0;
                    snowPositions[i].y = 0;
                }else if(snowPositions[i].x < -5){
                    snowPositions[i].x = window.innerWidth;
                    snowPositions[i].y = 0;
                }else{
                    snowPositions[i].x += (Math.floor(Math.random() * 10) + 1) - (Math.floor(Math.random() * 10) + 1);
                }
            }
            drowCanvas(snowPositions);
            updateCanvas(snowPositions);
        }, 150);
    };

    var drowCanvas = function(snowPositions){
        // クリア
        context.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
        for(var i in snowPositions){
            context.font = '20pt "JiyunoTsubasa"'; // フォント設定
            context.fillStyle = '#FFFFFF'; // 塗りつぶし色
            context.shadowColor = '#8F8FFF'; //影の色
            context.shadowBlur = (Math.floor(Math.random() * 10) + 10); // 影に適用するぼかし
            context.shadowOffsetX = 0; // 影のオフセット(X座標)
            context.shadowOffsetY = 0; // 影のオフセット(Y座標)
            context.fillText('雪', snowPositions[i].x, snowPositions[i].y);
        }
    };
})();

何か説明が必要な部分ありますかね?ないですよね.大丈夫ですよね.
Canvasでアニメーションをする場合,描いて消してを繰り返すかたちになります.
ランダムな値が必要な部分はいろいろ試行錯誤して,できるだけ雪っぽく見えるようにしました.

今回は以上になります.多分一週間後にまたまた登場予定です.
なんか,コード貼って終わりな感じがあるけどいいのでしょうか?

0 件のコメント:

コメントを投稿