·飞飞 - 2024-6-29 18:28
·悄然 - 2024-6-29 18:27
·飞飞 - 2024-6-29 13:18
·悄然 - 2024-6-29 10:18
·知名不具 - 2024-6-28 22:54
·知名不具 - 2024-6-28 22:08
·知名不具 - 2024-6-28 22:07
·知名不具 - 2024-6-28 22:04
·知名不具 - 2024-6-28 22:04
用canvas画布绘制一棵静态树
递归指的是一个函数在执行过程中调用自己、直至执行条件满足时终止函数的自执行。我们接触得最多的应该就是请求关键帧动画,我们把动画的执行机制做成一个函数,在函数内部使用 requestAnimationFrame() 反复调用该函数:
requestAnimationFrame() 方法是JS封装好的以显示刷新率为运行频率的API,它在函数 render() 的内部调用了函数 render() ;自身,使得函数要执行的任务得以不间断地执行。上例没有在函数内部提供任务终结的直接出口,而是通过请求关键帧动画标识 raf 用做开关,以便可以在函数的外部对动画的运行、暂停进行有效控制。不过地道的递归函数则应在函数内部提供出口条件,换言之,函数自身应该具备终止执行任务的条件,为此,我们在设计递归函数时,除了可以像上例那样可以在外部开、关函数的运行外,还应有能力在函数内部设立开、关逻辑清晰的运行机制,让递归函数适时终止自执行。以下例子,函数需要一个整数型参数,函数的任务是1加到该参数,就是等差数列求和,数学家高斯小时候做的1加到100的那个问题:
add(num) 函数首先设立一个条件,即代码第2行,如果参数 num ≤ 0 将返回 0,这个条件一旦满足,函数就会退出运行。第 4 行代码,整体意思是返回 num + add(num -1),这里信息量很庞大:return 是返回结果;而结果,首先是 num 自身,其次是它依次通过修改参数为 num - 1 来反复调用函数自身、直至参数 num ≤ 1 时把第二行的返回值也加上就退出累加工作。代码第 6 行,运行函数 add(num),传参是 100,并打印出最终累加结果。
需要特别注意,递归函数必须设计出口,以逻辑清晰的条件为临界,令任务执行完毕跳出任务的执行。递归递归,递是传递,将传递出去的指令一一落实,归就是回归,指令执行到满足条件了就要回头,不要无休止地干下去。
利用递归函数,我们可以在canvas画布上画一棵树,思路是这样子:
① 设计一个 draw 函数,需要 5 个参数:树干起始点XY坐标 sx 和 sy、树干单节长度 len、树干宽度 width、树干折向角度 deg;
② 接力绘制树干,每一次都将画布坐标系位移到(sx,sy)处、旋转画布坐标系 deg 个弧度。首次在外部调用函数时使用实数参数,内部的递归调用则依据情况按一定系数调整各个参数;
③ 以 len 参数即一节树干(后来变为树枝)的长度为出口参数,内部递归调用乘上一个小于 1 的参数,这样它不断变短——实际上从第二次开始它们变成了分岔的树枝——,当它短到一定的程度,退出递归调用,退出时还有一个重要的任务,绘制果实;
④ 函数内部要两次递归调用函数自身,实现树枝左右折向,同时也令绘制情景更为复杂化;
⑤ 我们需要树枝的折向角度不那么一致,以避免树的成品过于对称。
这样绘制出来的树不带叶子,适合在沙漠中生长,其果实可以加工成黑石浓缩饮料,价值连城。下面是完整代码:
可以将上述代码存为本地 .html 文档,或将代码拿到 pencil code,然后运行查看效果。
前一篇: 成吉思汗(歌词同步+小球碰撞演示)
下一篇: canvas画布:大白兔变大红兔
评论列表 [3条]
#3 | 小希 于 2024-4-19 20:46 发布: 沙漠中生长,其果实可以加工成黑石浓缩饮料~~看来可以多种一些,开辟黑石饮料原浆基地。
#2 | 飞飞 于 2024-4-19 20:42 发布: 递归函数这么复杂的绘制,代码并不冗长。设想得全面,连两边不要太对称都想到了。。。执行的精确,枝干由粗到细,最后自动画的彩色小果子也很诱人。。
#1 | 悄然 于 2024-4-19 20:35 发布: 同棵树的果子不可能这么五彩缤纷,所以这是一棵开花的树。。