Bạn có thể làm điều này bằng cách:
- Tạo một spline hồng y dựa trên dòng ngẫu nhiên chỉ
- Đi bộ dọc theo đường đó và vẽ một ngôi sao trên vị trí hiện tại
Tại sao hồng y spline? Một spline hồng y sẽ tạo ra một đường trơn tru giữa một tập hợp các điểm. Nếu cũng có giá trị độ căng. Bằng cách phóng đại giá trị độ căng (tức là ngoài phạm vi [0,1] bình thường) nó sẽ tạo ra các đường xoăn thay thế.
// draw example lines
var ctx = c.getContext("2d"), p = [0,100, 25,40, 50,70, 75,50, 100,80, 125,32, 150,100, 175,60];
ctx.font = "bold 16px sans-serif";
render(0); render(0.5); render(-2);
ctx.setTransform(1,0,0,1,0, 110);
render(-2, 3, "Segments: 3"); render(-2, 9, "Segments: 9"); render(-2, 25, "Segments: 25");
function render(t, seg, txt) {
ctx.beginPath();
ctx.moveTo(0, 100);
ctx.curve(p, t, seg || 20);
ctx.stroke();
ctx.fillText(txt ? txt : (!t ? "Plain poly-line" : "Cardinal, tension: " + t), 0, 20);
ctx.translate(200,0);
}
Chúng ta có thể tận dụng lợi thế của bất động sản này và vẽ một điểm dọc theo một dòng như vậy để tạo ra một phong trào chất lỏng-ish. Chuyển động có thể được tinh chế bằng cách de/tăng độ phân giải phân đoạn giữa mỗi dòng trong spline mà sẽ ảnh hưởng đến độ mượt cũng như tốc độ.
Các ưu điểm khác là chúng ta không phải tính toán bất kỳ thứ gì trong chính hình động (sẽ có "đỉnh" ban đầu khi thiết lập các điểm (cache)), chúng ta chỉ cập nhật con trỏ mảng và kết xuất. Và sự phân bố sẽ là khá ngay cả khi các điểm là các lực dọc theo các đường phân bố đồng đều (vô hình).
Làm thế nào để thực hiện nó có thể thay đổi tất nhiên - đây là một ví dụ về một cách tiếp cận:
Ví dụ thực hiện
Xác định một đối tượng sao (nó thực sự cần được prototyped nhưng vì lợi ích của bản demo):
function Star(ctx, xseg) {
var points = [], // holds points for cardinal points
cPos = 0, oPos = -1, // positions in line
len,
w = ctx.canvas.width,
x = -10, y = -10;
// this iterates and loop the point list
this.animate = function() {
cPos++;
if (cPos > len - 2) {
cPos = 0; oPos = -1;
}
var pos = cPos * 2;
x = points[pos];
y = points[pos + 1];
drawStar();
}
// render some star
function drawStar() {
ctx.rect(x, y, 2, 2);
}
// This generate a set of random points, then converts those into
// points for a cardinal spline (linked as script).
function generatePath() {
var w = ctx.canvas.width,
h = ctx.canvas.height,
numOfSeg = 20,
dh = h/numOfSeg,
i= 0, l, x, y;
for(; i<= numOfSeg; i++) {
x = xseg + w/8 * Math.random();
y = h - (i * dh + ((dh/2) * Math.random() - (dh/4)));
points.push(x, y);
}
points = curve(points, -2, 200 * Math.random() + 100);
l = points.length;
// adjust for out of edges
for(i = 0; i < l; i += 2) if (points[i] > w) points[i] -= w;
len = points.length/2;
cPos = parseInt(len * Math.random());
}
generatePath();
}
Full dụ
function Star(ctx, xseg) {
var points = [], // holds points for cardinal points
cPos = 0, oPos = -1, // positions in line
len,
w = ctx.canvas.width,
x = -10, y = -10;
this.animate = function() {
cPos++;
if (cPos > len - 2) {
cPos = 0; oPos = -1;
}
var pos = cPos * 2;
x = points[pos];
y = points[pos + 1];
drawStar();
};
function drawStar() {
ctx.moveTo(x + 2, y);
ctx.arc(x, y, 2, 0, Math.PI*2);
}
function generatePath() {
var w = ctx.canvas.width,
h = ctx.canvas.height,
numOfSeg = 20,
dh = h/numOfSeg,
i= 0, l, x, y;
for(; i <= numOfSeg; i++) {
x = xseg + w/8 * Math.random();
y = h - (i * dh + ((dh/2) * Math.random() - (dh/4)));
points.push(x, y);
}
points = getCurvePoints(points, -2, (400 * Math.random() + 200)|0);
l = points.length;
for(i = 0; i < l; i += 2) if (points[i] > w) points[i] -= w;
len = points.length/2;
cPos = (len * Math.random())|0;
}
generatePath();
}
// Main code
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
stars = [],
numOfStars = 100,
segs = canvas.width/numOfStars,
i = 0,
throttle = 0,
delay = 2;
// create stars
for(; i < numOfStars; i++) stars.push(new Star(ctx, i * segs - segs));
ctx.fillStyle = "#fff";
ctx.shadowColor ="#fff";
ctx.shadowBlur = 7;
// ANIMATE
(function animate() {
if (!throttle) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
for(var i = 0; i < stars.length; i++) stars[i].animate();
ctx.fill();
}
throttle++;
if (throttle === delay) throttle = 0;
requestAnimationFrame(animate);
})();
Xem đồng de để thực hiện spline hồng y trong this answer.
Cách tiếp cận khác là sử dụng các hạt và biến đổi vận tốc bằng cách sử dụng ví dụ như một hàm xoang. Để làm việc này tối ưu, bạn có thể cần một tốc độ lưới để thay đổi ảnh hưởng đến một hạt dựa trên vị trí. Lưới có thể có hướng ngẫu nhiên và vận tốc.
Tôi sẽ sử dụng chức năng giảm tốc để giảm tốc/tăng tốc các hạt khi chúng thay đổi hướng. – Eduardo
Tôi nghĩ rằng điều chính khiến nó trông "không tự nhiên" đối với tôi là tất cả chúng đều có những thay đổi hướng lớn về cơ bản cùng một lúc. Tất nhiên, tôi đang tưởng tượng họ như là lỗi như vậy .. –