5.10 创建微生物生命形态
你曾经在显微镜下看到过微生物生命形态,并观察它们是如何四处扭动吗?本节就是受微生物世界的启发而产生的。本节,我们将随机创建100个的微生物,并让它们散落在画布上。
操作步骤
按照以下步骤,创建在画布内随意扭动的微生物:
1. 链接到Animation类:
<head>
<script src="animation.js">
</script>
2. 定义getRandColor()函数,该函数返回一个随机的颜色:
<script>
function getRandColor(){
var colors = ["red", "orange", "yellow", "green", "blue", "violet"];
return colors[Math.floor(Math.random() * colors.length)];
}
3. 定义getRandTheta()函数,该函数返回一个随机的角度:
function getRandTheta(){
return Math.random() * 2 * Math.PI;
}
4. 定义updateMicrobes()函数,该函数使用随机产生的角度为每个微生物添加头部,并去掉其尾部,来更新microbe对象:
function updateMicrobes(anim, microbes){
var canvas = anim.getCanvas();
var angleVariance = 0.2;
for (var i = 0; i < microbes.length; i++) {
var microbe = microbes[i];
var angles = microbe.angles;
/*
* good numNewSegmentsPerFrame values: * 60fps -> 1
* 10fps -> 10
*
* for a linear relationship, we can use the equation:
* n = mf + b, where n = numNewSegmentsPerFrame and f =
FPS
* solving for m and b, we have: * n = (-0.18)f + 11.8
*/
var numNewSegmentsPerFrame = Math.round(-0.18 * anim.getFps() + 11.8);
for (var n = 0; n < numNewSegmentsPerFrame; n++) {
// create first angle if no angles
if (angles.length == 0) {
microbe.headX = canvas.width / 2;
microbe.headY = canvas.height / 2;
angles.push(getRandTheta());
}
var headX = microbe.headX;
var headY = microbe.headY;
var headAngle = angles[angles.length - 1];
// create new head angle
var dist = anim.getTimeInterval() / (10 * numNewSegmentsPerFrame);
// increase new head angle by an amount equal to
// -0.1 to 0.1
var newHeadAngle = headAngle + ((angleVariance / 2) - Math.random() * angleVariance);
var newHeadX = headX + dist * Math.cos(newHeadAngle);
var newHeadY = headY + dist * Math.sin(newHeadAngle);
//发生碰撞后改变方向
if (newHeadX >= canvas.width || newHeadX <= 0
|| newHeadY >= canvas.height || newHeadY <= 0) {
newHeadAngle += Math.PI / 2;
newHeadX = headX + dist * Math.cos(newHeadAngle);
newHeadY = headY + dist * Math.sin(newHeadAngle);
}
microbe.headX = newHeadX;
microbe.headY = newHeadY;
angles.push(newHeadAngle);
//去掉尾部角度
if (angles.length > 20) {
angles.shift();
}
}
}
}
5. 定义drawMicrobes()函数,该函数绘制所有微生物:
function drawMicrobes(anim, microbes){
var segmentLength = 2; // px
var context = anim.getContext();
for (var i = 0; i < microbes.length; i++) {
var microbe = microbes[i];
var angles = microbe.angles;
context.beginPath();
context.moveTo(microbe.headX, microbe.headY);
var x = microbe.headX;
var y = microbe.headY;
// 从头部开始,到尾巴结束
for (var n = angles.length - 1; n >= 0; n--) {
var angle = angles[n];
x -= segmentLength * Math.cos(angle);
y -= segmentLength * Math.sin(angle);
context.lineTo(x, y);
}
context.lineWidth = 10;
context.lineCap = "round";
context.lineJoin = "round";
context.strokeStyle = microbe.color;
context.stroke();
}
}
6. 实例化一个Animation对象,并得到画布上下文对象:
window.onload = function(){
var anim = new Animation("myCanvas");
var canvas = anim.getCanvas();
var context = anim.getContext();
7. 初始化100个微生物:
//初始化微生物
var microbes = [];
for (var n = 0; n < 100; n++) {
// 每个微生物都是一个角度的数组
microbes[n] = {
headX: 0,
headY: 0,
angles: [],
color: getRandColor()
};
}
8. 设置stage()函数,该函数通过调用updateMicrobes()函数来更新微生物,清除画布,然后调用drawMicrobes()函数绘制微生物:
anim.setStage(function(){
// update
updateMicrobes(this, microbes);
// clear
this.clear();
// draw
drawMicrobes(this, microbes);
});
9. 启动动画:
anim.start();
};
</script>
</head>
10. 在HTML文档的body部分嵌入canvas标签:
<body>
<canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
</canvas>
</body>
工作原理
要创建微生物,我们可以绘制一系列连接的小段来创建一个短小的蛇形生物。我们可以把一个微生物为表示一个对象,该对象包含一个头部位置和一个角度的数组。这些角度代表各段之间的夹角。
本节创建了100个随机的微生物,并把它们放置在画布的中央。我们的stage()函数包含updateMicrobes()函数和drawMicrobes()函数。
updateMicrobes ()函数循环所有的微生物对象,为每个微生物其增加一个头段,并去掉其尾段。用这个办法,当每个微生物在画布上移动时,将会发生扭动。当微生物的头碰到画布边缘,其角度会增加90°,以便能够弹回到画布区域。
drawMicrobes()函数循环所有的微生物对象,把绘制光标定位到每个微生物的头部,然后根据每段的角度绘制20条线段。
相关参考
- 第1章 绘制弹簧
- 第6章 创建绘图应用