JavaScript · 3232 bytes Raw Blame History
1 // Pond module - handles the water, shore, and fence rendering (p5.js version)
2
3 export class Pond {
4 constructor(p, x, y, width, height) {
5 this.p = p
6 this.x = x
7 this.y = y
8 this.width = width
9 this.height = height
10 this.ripples = []
11 }
12
13 contains(px, py) {
14 const dx = (px - this.x) / (this.width / 2)
15 const dy = (py - this.y) / (this.height / 2)
16 return (dx * dx + dy * dy) <= 1
17 }
18
19 addRipple(x, y) {
20 this.ripples.push({
21 x,
22 y,
23 radius: 5,
24 maxRadius: 40,
25 alpha: 150
26 })
27 }
28
29 update() {
30 for (let i = this.ripples.length - 1; i >= 0; i--) {
31 const ripple = this.ripples[i]
32 ripple.radius += 0.8
33 ripple.alpha -= 3
34 if (ripple.alpha <= 0) {
35 this.ripples.splice(i, 1)
36 }
37 }
38 }
39
40 draw() {
41 const p = this.p
42 const outlineColor = p.color(25, 20, 15)
43 const outlineWeight = 2.5
44
45 // Grassy shore area
46 p.stroke(outlineColor)
47 p.strokeWeight(outlineWeight)
48 p.fill(120, 180, 90)
49 p.ellipse(this.x, this.y, this.width + 70, this.height + 55)
50
51 // Shore highlight
52 p.noStroke()
53 p.fill(150, 210, 110)
54 p.ellipse(this.x - 30, this.y - 20, this.width * 0.4, this.height * 0.25)
55
56 // Sandy edge
57 p.stroke(outlineColor)
58 p.strokeWeight(outlineWeight)
59 p.fill(190, 160, 110)
60 p.ellipse(this.x, this.y, this.width + 25, this.height + 18)
61
62 // Pond water
63 p.stroke(outlineColor)
64 p.strokeWeight(outlineWeight)
65 p.fill(70, 160, 190)
66 p.ellipse(this.x, this.y, this.width, this.height)
67
68 // Water cel-shaded bands
69 p.noStroke()
70 p.fill(50, 130, 160)
71 p.ellipse(this.x + 20, this.y + 30, this.width * 0.7, this.height * 0.4)
72
73 p.fill(110, 200, 220)
74 p.ellipse(this.x - this.width * 0.18, this.y - this.height * 0.18, this.width * 0.45, this.height * 0.28)
75
76 p.fill(160, 230, 245)
77 p.ellipse(this.x - this.width * 0.22, this.y - this.height * 0.22, this.width * 0.2, this.height * 0.12)
78
79 // Ripples
80 p.noFill()
81 for (const ripple of this.ripples) {
82 p.stroke(255, 255, 255, ripple.alpha)
83 p.strokeWeight(2.5)
84 p.ellipse(ripple.x, ripple.y, ripple.radius * 2, ripple.radius * 1.3)
85 }
86 p.noStroke()
87
88 this.drawFence()
89 }
90
91 drawFence() {
92 const p = this.p
93 const fenceX = this.x + this.width / 2 + 50
94 const fenceStartY = this.y - 90
95 const postCount = 5
96 const postSpacing = 38
97 const outlineColor = p.color(25, 20, 15)
98
99 for (let i = 0; i < postCount; i++) {
100 const postY = fenceStartY + i * postSpacing
101 const wobble = p.sin(i * 1.5) * 5
102
103 p.stroke(outlineColor)
104 p.strokeWeight(2)
105 p.fill(180, 130, 70)
106 p.push()
107 p.translate(fenceX + wobble, postY)
108 p.rotate(p.radians(wobble * 0.6))
109 p.rect(-5, -22, 10, 44, 2)
110
111 p.noStroke()
112 p.fill(210, 165, 100)
113 p.rect(-3, -20, 4, 40, 1)
114 p.pop()
115 }
116
117 p.stroke(outlineColor)
118 p.strokeWeight(2)
119 p.fill(165, 120, 65)
120 p.push()
121 p.translate(fenceX - 2, fenceStartY - 8)
122 p.rotate(p.radians(2))
123 p.rect(-6, -4, 12, 8, 2)
124 for (let i = 1; i < postCount; i++) {
125 p.rect(-6 + i * 2, -4 + i * postSpacing, 12, 8, 2)
126 }
127 p.pop()
128
129 p.noStroke()
130 }
131 }