【100sites #009】Flame,P5js酷炫小動畫

Posted by Eason Chang on 2016-03-23

一句話摘要:使用P5.js製作的類火焰互動效果

玩線上Demo

查看Github原始碼

螢幕快照 2016-03-23 上午4.08.53.png

我會知道P5.js的存在,是因為在今年SITCON年會上聽了游宭鎬(Chiun Hau You)先生的分享,而最近看他用P5.js做的視覺辨識專案: Hello World - Programmable Visual Identity上了CodePen的Picked Pens,迴響熱烈,讓我也開始想探索P5.js更多的可能性,於是做了今天的小火焰互動特效練習。

今天沒什麼細節要講,移動你的滑鼠,享受這些小火焰吧!

點滑鼠左鍵可以切換樣式,共有4種樣式。

另外一種樣式:
螢幕快照 2016-03-23 上午4.09.52.png

原始碼:

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset-"UTF-8">
<title>Flame</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.23/p5.js"></script>
<script src="flame.js"></script>
</head>

<body>
</body>
</html>
style.css
1
2
3
4
5
6
7
8
* {
margin: 0;
padding: 0;
}

body {
overflow: hidden;
}
flame.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
var rows = 0, // how many shapes there are vertically
cols = 0, // how many shapes there are horizontally
diameter = [], // diameter of every single shape
displayMode = 0, // four display mode: 0: red rect, 1: red ellipse, 2: blue rect, 3: blue ellipse
MARGIN = 30, // distance between two shapes
MAX_SIZE = 100, // max shape size when mouse approach
SENSE_RANGE = 200; // what distance shapes will react

function setup() {

createCanvas(windowWidth, windowHeight);
strokeWeight(0);
ellipseMode(CENTER);
rectMode(CENTER);
frameRate(30);

rows = windowHeight / MARGIN;
cols = windowWidth / MARGIN;

// initialize diameter 2-dimensional array
for (var y = 0; y < rows; ++y) {
diameter.push([]);
for (var x = 0; x < cols; ++x) {
diameter[y].push(0);
}
}
}

function draw() {

background(20);
for (var y = 0; y < rows; y += 1) {
for (var x = 0; x < cols; x += 1) {
var thisDiameter = diameter[y][x];

// decrease diameter by time until diameter is 0
if (thisDiameter < 2) {
diameter[y][x] = 0;
} else { // thisDiameter >= 2
diameter[y][x] -= 2;
thisDiameter = diameter[y][x];

// And we can now display it
// Determine which color should we use
if (displayMode <= 1) { // 0, 1
fill(255,thisDiameter*2.5,0); // red color mode
} else { // 2, 3
fill(0,thisDiameter*2.5,255-thisDiameter*1.5); // blue color mode
}
// Determine which shape should we use
if (displayMode == 0 || displayMode == 2) { // 0, 2
rect(x*MARGIN, y*MARGIN, thisDiameter, thisDiameter); // rect mode
} else { // 1, 3
ellipse(x*MARGIN, y*MARGIN, thisDiameter, thisDiameter); // ellipse mode
}
} // .if-else
} // .for
} // .for
}

// when mouse moved, adjust diameters of every shapes
function mouseMoved() {

for (var y = 0; y < rows; y += 1) {
for (var x = 0; x < cols; x += 1) {
// calculus the distance between this shape and user mouse
var dist = Math.sqrt((x*MARGIN-mouseX)*(x*MARGIN-mouseX)+(y*MARGIN-mouseY)*(y*MARGIN-mouseY));
if (dist <= SENSE_RANGE) {
// calculus the diameter based on the distance
var theDiameter = (SENSE_RANGE - dist)*MAX_SIZE/SENSE_RANGE;
// if current diameter is smaller than the calc diameter
if (diameter[y][x] < theDiameter) {
diameter[y][x] = theDiameter; // increase the current diameter to it should be
}
}
}
}
}

// switch display mode
function mousePressed() {
++displayMode;
if (displayMode > 3) {
displayMode = 0;
}
}