随机数的魅力 一

在程序设计中,随机数是最令我着迷的。我厌恶宿命论。
《javascript高效图形编程》中,有个例子很好的展现了随机的魅力,每次运行都会得到一颗不一样的树。如下,
这里写图片描述

javascript 代码

<!DOCTYPE html>
<html>
    <head>
        <title>
            Recursive Canvas Tree
        </title>
        <script type="text/javascript" 
            src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js">
        </script>
        <script type="text/javascript">

        var drawTree = function (ctx, startX, startY, length, angle, depth, branchWidth) {
            var rand = Math.random,
                newLength, newAngle, newDepth, maxBranch = 3,
                endX, endY, maxAngle = 2 * Math.PI / 4,
                subBranches, lenShrink;
            // Draw a branch, leaning either to the left or right (depending on angle).
            // First branch (the trunk) is drawn straight up (angle = 1.571 radians)
            ctx.beginPath();
            ctx.moveTo(startX, startY);
            endX = startX + length * Math.cos(angle);
            endY = startY + length * Math.sin(angle);

            ctx.lineCap = 'round';
            ctx.lineWidth = branchWidth;
            ctx.lineTo(endX, endY);

            // If we are near the end branches, make them green to look like leaves.
            if (depth <= 2) {
                ctx.strokeStyle = 'rgb(0,' + (((rand() * 64) + 128) >> 0) + ',0)';
            }
            // Otherwise choose a random brownish color.
            else {
                ctx.strokeStyle = 'rgb(' + (((rand() * 64) + 64) >> 0) + ',50,25)';
            }
            ctx.stroke();

            // Reduce the branch recursion level.
            newDepth = depth - 1;
            // If the recursion level has reached zero, then the branch grows no more.
            if (!newDepth) {
                return;
            }
            // Make current branch split into a random number of new branches (max 3).
            // Add in some random lengths, widths and angles for a more natural look.
            subBranches = (rand() * (maxBranch - 1)) + 1;
            // Reduce the width of the new branches.
            branchWidth *= 0.7;
            // Recursively call drawTree for the new branches with new values.
            for (var i = 0; i < subBranches; i++) {
                newAngle = angle + rand() * maxAngle - maxAngle * 0.5;
                newLength = length * (0.7 + rand() * 0.3);
                drawTree(ctx, endX, endY, newLength, newAngle, newDepth, branchWidth);
            }
        };

            $(document).ready(function() {
                var canvas = document.getElementById('mycanvas');
                var ctx = canvas.getContext('2d');
                drawTree(ctx, 320, 470, 60, -Math.PI / 2, 12, 12);
            });
        </script>
    </head>
    <body>
        <canvas id="mycanvas" width=640, height=480></canvas>
        </div>
    </body>
</html>

我在这个例子的基础,将其改成了动画,上面的例子用了递归,一种深度优先遍历,而我把它改为了广度优先遍历,非递归的。生成的树,如下,
这里写图片描述

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="640" height="480" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

var drawGrowingTree = function (ctx, map, maxDepth, levelRenderTime, time) {
            ctx.fillStyle = "rgb(0,0,255)";
            var time2 = (time / levelRenderTime) >> 0;
            var progress = time % levelRenderTime + 1;
            var level = maxDepth - time2;
            if (level < 0 ) {
                clearInterval(animId);
                console.log("clearInterval: " + animId);
                return;
            }

            for (var i = 0; i < map[level].length; i++) {
                var branch = map[level][i];
                ctx.beginPath();
                ctx.moveTo(branch.start_x, branch.start_y);
                ctx.lineCap = 'round';
                ctx.lineWidth = branch.width;
                var len = branch.len * progress / levelRenderTime;
                var endX = Number(branch.start_x) + Number(len * Math.cos(branch.angle) );
                var endY = Number(branch.start_y) + Number(len * Math.sin(branch.angle) );
                ctx.lineTo(endX.toFixed(3), endY.toFixed(3));
                ctx.strokeStyle = branch.color;
                ctx.stroke();

            }
        }

        var createTree = function (startX, startY, length, angle, depth, branchWidth) {
            var rand = Math.random, maxBranch = 3,
                maxAngle = 2 * Math.PI / 4;
            var queue = [];
            var endX = startX + length * Math.cos(angle);
            var endY = startY + length * Math.sin(angle);
            queue.push({
                start_x: startX,
                start_y: startY,
                end_x: endX,
                end_y: endY,
                angle: angle,
                len: length,
                depth: depth,
                width: branchWidth,
                // Otherwise choose a random brownish color.
                color: 'rgb(' + (((rand() * 64) + 64) >> 0) + ',50,25)'
            });
            var index = 0;
            var cur = queue[index];
            var map = [];
            map[depth] = [cur];
            for (var i = 0; i < depth; i++) {
                map[i] = [];
            }
            while (cur.depth > 0) {
                // Make current branch split into a random number of new branches (max 3, min 1).
                // Add in some random lengths, widths and angles for a more natural look.
                var subBranches = (rand() * (maxBranch - 1)) + 1;
                // subBranches = subBranches >> 0;
                // console.log("subBranches: " + subBranches);
                // Reduce the width of the new branches.
                var childWidth = cur.width * 0.7;
                var childDepth = cur.depth - 1;
                var childColor;
                if (cur.depth <= 2) {
                    childColor = 'rgb(0,' + (((rand() * 64) + 128) >> 0) + ',0)';
                }
                // Otherwise choose a random brownish color.
                else {
                    childColor = 'rgb(' + (((rand() * 64) + 64) >> 0) + ',50,25)';
                }
                // Recursively call drawTree for the new branches with new values.
                for (var i = 0; i < subBranches; i++) {
                    var newAngle = cur.angle + rand() * maxAngle - maxAngle * 0.5;
                    var newLength = cur.len * (0.7 + rand() * 0.3);
                    endX = Number(cur.end_x) + Number(newLength * Math.cos(newAngle) );
                    endY = Number(cur.end_y) + Number(newLength * Math.sin(newAngle) );
                    var obj = {
                        start_x: cur.end_x,
                        start_y: cur.end_y,
                        end_x: Number(endX).toFixed(3),
                        end_y: Number(endY).toFixed(3),
                        angle: newAngle,
                        len: newLength,
                        depth: childDepth,
                        width: childWidth,
                        color: childColor
                    };
                    queue.push(obj);
                    map[childDepth].push(obj);
                }
                index++;
                cur = queue[index];
            }
            return map;
        }

        var maxDepth = 9;
        var treeMap = createTree(320, 470, 60, -Math.PI / 2, maxDepth, 12);
        var time = 0;

        var animId = setInterval(function() {
            drawGrowingTree(ctx, treeMap, maxDepth, 3, time);
            time++;
        }, 20);


</script>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/mu399/article/details/78997279