山水特效[1] - 随机绘制层峦叠嶂的山水画

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
var WIDTH = 1200
var HEIGHT =200
var game = new PIXI.Application({
width: WIDTH,
height: HEIGHT,
transparent: true,
backgroundColor: 0xffffff
})
document.getElementById('preview-box').appendChild(game.view)
game.view.style.width = "100%"
/**
* 先编写绘制一层山的方法
* @param {number} startX 开始x坐标
* @param {number} endX 结束y坐标
* @param {number} heightLimit 图形高度限制
* @param {number} sharpConfig 锐度,数值越大越锋利,默认是heightLimit/30
* @returns array
*/
function drawMountain(startX, endX, heightLimit, sharpConfig) {
var step = 40 // 精度,整个画面,x轴分成多少等分
var sharp = sharpConfig || heightLimit / 30 // 锐度,其实就是两个折点之间的最大高度差
var space = (endX - startX) / step // 精度,整个画面,x轴以多少距离进行等分,值越小,山峰数量越多
var path = []
for (var i = 0; i <= step; i++) {
// 距离中心的系数,越靠近中心,系数越接近1,越原理,越趋近于0
var ratio = Math.sin(Math.PI * i / step)
var x = Math.round(startX + (space * i))
var y = -1

if (i === 0 || i === step) {
y = 0
} else {
// 当y值超过底边时,重新计算
while (y >= heightLimit || y < 0) {
y = Math.round(((Math.random() * 2 - 1) * sharp + path[2 * i - 1]) * ratio)
}
}
path.push(x, y)
}
return path
}

// 翻转数组中的y坐标
function rotateArrY(arr) {
return arr.map(function (num, i) {
if (i % 2 === 1) {
return HEIGHT - num
} else {
return num
}
})

}

//
function main() {
// 清除上次绘画
game.stage.removeChildren();
let colors = createColorArr(3)

// 远端
var grapFar = new PIXI.Graphics();
grapFar.name = 'far'
var pathFar = drawMountain(0, WIDTH, HEIGHT,40)
grapFar.lineStyle(0);
grapFar.beginFill(colors[0], .4);
grapFar.drawPolygon(rotateArrY(pathFar));
grapFar.endFill();
game.stage.addChild(grapFar);

// 中层
var grapMid = new PIXI.Graphics();
grapMid.name = 'mid'
var pathMid = drawMountain(0, WIDTH, HEIGHT,30)
grapMid.lineStyle(0);
grapMid.beginFill(colors[1], .7);
grapMid.drawPolygon(rotateArrY(pathMid));
grapMid.endFill();
game.stage.addChild(grapMid);

// 近层
var grapNear = new PIXI.Graphics();
grapNear.name = 'near'
var pathNear = drawMountain(0, WIDTH, HEIGHT,30)
grapNear.lineStyle(0);
grapNear.beginFill(colors[2], 1);
grapNear.drawPolygon(rotateArrY(pathNear));
grapNear.endFill();
game.stage.addChild(grapNear);

document.onmousemove = throttle(function(event){
var move = event.clientX - window.innerWidth/2
grapFar.x = move * -0.01
grapMid.x = move * 0.02
grapNear.x = move * 0.03
},16.6*2)

document.onmouseleave= function(){
grapFar.x = 0
grapMid.x = 0
grapNear.x = 0
}
}

main()
document.getElementById('draw').onclick = function () {
main()
}

// 节流
function throttle(fn,time){
let inter;
return function(){
let context = this;
if(!inter){
inter = setTimeout(()=>{
inter = null;
},time)
fn.apply(context,arguments)
}
}
}

// 创建多组随机颜色
function createColorArr(num) {
let arr = []
for (let n = 0; n < num; n++) {
arr.push(PIXI.utils.rgb2hex([
Math.random() * .7,
Math.random() * 1,
Math.random() * .4,
]))
}
return arr
}