将前两天画好的树枝骨干,搭配第二章学的动画效果,就能让树开始摆动了:
https://jerry-the-potato.github.io/Chapter3-demo-object/
当然,由於参数ab设置过头,滑鼠移动到边边角角时,整棵树变得很奇怪(我看像是稻穗!不,是棋盘!)
看完之後,是不是有发现卡卡的呢?(如果没有可能是你的绘图处理器太给力了XD)
原因就出在昨天卖的一个关子:「单纯用如此简单的物件结构,会导致过多重复的代码」
用Edge浏览器可以看到,JS占用了相当大的容量和CPU:
已经会导致掉侦的程度了,真的是很母汤呢!
把结构修改後:
改动的地方非常少:
Class把原本的建构式拆出来写,结构上可以较清楚在实例化的当下会建构哪些变数
其实不是物件不好用,而是还没有跟大家说prototype的概念,这个下礼拜会有两个篇幅的故事来解释,今天就简单用现实生活比喻,糖尿病会遗传这个是大家都知道的,但是我现在又没有糖尿病,怎麽知道未来有没有机会得呢?医生会去看我的家族史,往上追本溯源,看有没有人得过糖尿病。
在这个案例中,我遗传(继承)了我家族的疾病,而为了评估得病的风险,就要去看生我的人(爸爸的prototype),父辈祖辈一直往上,因此,只要我家族有人得过遗传病,接下来好几代的子孙都有得病风险。
以程序的观点来说,就是当我要把整个家族的病历给归档的时候,或是上帝要决定谁会得病(虚拟世界!?),最麻烦的方式就是给每个个体做标记,一出生的时候就写说,这个人有10%、那个人有20%,如果是这样,光是一个糖尿病就要给每个人都贴过一次标签,要设定无数个变数。反过来讲,最简单的方式,就是只标记那个得糖尿病的爷爷,这样,虽然我没办法直接知道每个个体的得病机率,但是可以透过他们跟爷爷的血缘关系(继承链),来得知结果,这样一来就只需要在爷爷身上设定一个变数,就可以解决问题了。
观念说清楚了,就可以实作:
效能也更好了
归根结柢也是因为给每节树枝设的变数太多,等到时候开始做游戏再来简化
因为有不少变因,像是:
像是滑鼠点击时产生新的树,但是旧的树还没有触发JS的自动回收机制,假设一直连点滑鼠,JS堆积大小会来到20MB,过一阵子後,才会看到降回5MB左右,这是由於myTree这个变数不再指向那些旧的树,被JS自动回收机制认为是垃圾,才清除掉,这期间存在一个缓冲期。
以及如果只是重新整理页面会有残留的JS堆积,所以以上的图片数据皆不准!实际上实测的结果并没有什麽差异。
不过时间已经不够再深入研究了ww,日後再回来修改,继续我们的画树之旅吧!
这边我们用最懒的方法,直接让透明度渐变,使树干到树枝末端呈现透明度1~0.5的渐变:
let alpha = 0.5 + 0.5 * (r / (window.innerHeight/3));
context.strokeStyle = 'rgba(179, 198, 213, ' + alpha + ')';
为了看起来不那麽突兀,要让树从一个原点生出,当初原点是设置在(WIDTH/2, HEIGHT),因此减去这个位置,取得相对座标,接着设置一个this.grow参数,让树再建立之初以0.1开始,慢慢增加,若每次增加0.01会显得平铺直叙太无聊,因此模仿一下缓冲函式,让this.grow成长到一定程度後,就开始变慢:
let x = (this.startX - WIDTH / 2) * this.grow + WIDTH / 2,
y = (this.startY - HEIGHT) * this.grow + HEIGHT,
r = this.r * this.grow,
this.grow = Math.min(this.grow + 0.01 / (0.8 + 2 * this.grow), 1);
Tree.prototype.Draw = function () {
let x = (this.startX - WIDTH / 2) * this.grow + WIDTH / 2,
y = (this.startY - HEIGHT) * this.grow + HEIGHT,
r = this.r * this.grow,
theta = this.theta;
context.beginPath();
context.moveTo(x, y);
context.lineTo(x + r * Math.cos(theta / 180 * Math.PI),
y + r * Math.sin(theta / 180 * Math.PI));
context.lineWidth = 1 + r / 50;
let alpha = 0.5 + 0.5 * (r / (window.innerHeight/3));
context.strokeStyle = 'rgba(179, 198, 213, ' + alpha + ')';
context.stroke();
// 如果有子树枝,就继续呼叫所有的子树枝
if (this.son) this.son.forEach(branch => branch.Draw()); // 递回
this.grow = Math.min(this.grow + 0.01 / (0.8 + 2 * this.grow), 1);
};
ARM 版本的 Windows 该怎麽买呢? 主要的产品为 Surface Pro X ,这是一款微...
Xcode 版本 12.5 介面 点选 ios app 建立专案范本,范本有内建预设程序码,协助快速...
吃角子老虎机 教学原文参考:吃角子老虎机 这篇文章会介绍如何使用「函式」、「计次回圈」、「随机取数」...
如标题,这篇想教大家如何在phpMyAdmin里「手动」建立资料表 还有char和varchar的差...
环境安装的最後一个环节,就是安装我们的开发工具,本篇教学使用Spring Tool Suite (S...