-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWater Waves.py
254 lines (167 loc) · 7.63 KB
/
Water Waves.py
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
import pygame
from pygame.locals import *
from threading import Thread
import time
"""
Informations:
Simple script that shows how to make 2d waves with Pygame.
I created this program with a good tutorial on this page:
--> https://gamedevelopment.tutsplus.com/tutorials/make-a-splash-with-dynamic-2d-water-effects--gamedev-236
This program use the Threads, with this module you can change the FPS constants destined to Pygame and consequently accelerate the program
but nothing changes because the Update() function is not connected with the Pygame's framerate.
There are other methods but i have chosen this one.
This program is not very fast because too much springs are used, you can modify the script to optimize it.
You can release some springs and create a draw system with 2d polygons to make the script faster and more optimized.
"""
# Constants
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 400
CAPTION = "Waves Simulation with Pygame"
FPS = 60
BLUE = (0, 103, 247)
WHITE = (255, 255, 255)
class Main:
def __init__(self):
"""Main class"""
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption(CAPTION)
self.time = pygame.time.Clock()
self.target_height = 200 ## Max wave height and stable point
self.tension = 0.025
self.dampening = 0.020
self.spread = 0.25
self.height_splash = 5 ## Number of loop round // Warnning with a too hight value on this variable, the script will be very slower
self.init_speed = 200 ## Initial speed
self.init_position_x = 0 ## first position
self.final_position_x = 400 ## second_position
self.springs = [] ## List of objects (here the objects are Springs)
self.number_rod = self.create_number_rod()
self.rod_width = self.create_rod_width()
self.init_index = int(self.number_rod / self.rod_width)
self.create_spring_list(self.rod_width)
self.start_water_waves(self.rod_width)
self.done = False
self.run_game()
def run_game(self):
"""Main loop"""
while not self.done:
for event in pygame.event.get():
if event.type == QUIT:
self.done = True
pygame.quit()
exit()
if event.type == MOUSEBUTTONUP:
if self.counter.done == True:
pos = pygame.mouse.get_pos()
self.init_index = int(pos[0] / self.final_position_x * self.number_rod)
self.start_water_waves(self.rod_width)
self.draw_level()
for spring in self.springs:
spring.draw(self.screen)
self.time.tick(FPS) ## Set a FPS constants but you can change it
pygame.display.flip()
def create_number_rod(self):
"""Have half rod on all the water"""
return abs(int((self.init_position_x - self.final_position_x) / 2))
def create_rod_width(self):
"""Make an size average thank to the number of rod"""
return int((self.init_position_x + self.final_position_x) / self.number_rod)
def create_spring_list(self, rod_width):
"""Create the spring list"""
for x in range(self.init_position_x, self.final_position_x, rod_width):
self.springs.append(Spring(x, self.target_height, rod_width))
def start_water_waves(self, rod_width):
"""Start the waves motion at a given position"""
self.springs[self.init_index].speed = self.init_speed
self.counter = Counter_Waves_Motion(self)
self.counter.start()
def update(self):
"""Update the waves"""
self.update_waves()
self.create_neighbour_list()
self.update_neighbour()
self.test_end_water_waves()
def test_end_water_waves(self):
"""Check if the waves are still alive"""
count = 0
for i in range(len(self.springs)):
if not int(self.springs[i].speed) and not int(self.springs[i].y):
count += 1
if count == len(self.springs):
self.stop_water_motion()
def stop_water_motion(self):
"""Stop the motion of the water"""
for i in range(len(self.springs)):
self.springs[i].speed = 0
self.springs[i].height = self.target_height
self.springs[i].y = 0
def update_waves(self):
"""Update the water waves
of all the rod in the springs list"""
for i in range(len(self.springs)):
self.springs[i].update(self.dampening, self.tension, self.target_height)
def create_neighbour_list(self):
"""Create the lists of height
difference between the rods without reference"""
self.lDeltas = list(self.springs)
self.rDeltas = list(self.springs)
def update_neighbour(self):
"""Update the rod beside another"""
for j in range(self.height_splash):
for i in range(len(self.springs)):
if i > 0:
self.lDeltas[i] = self.spread * (self.springs[i].height - self.springs[i - 1].height)
self.springs[i - 1].speed += self.lDeltas[i]
if i < len(self.springs) - 1:
self.rDeltas[i] = self.spread * (self.springs[i].height - self.springs[i + 1].height)
self.springs[i + 1].speed += self.rDeltas[i]
self.termine_update_neighbour()
def termine_update_neighbour(self):
"""Terminate the procedure"""
for i in range(len(self.springs)):
if i > 0:
self.springs[i - 1].height += self.lDeltas[i]
if i < len(self.springs) - 1:
self.springs[i + 1].height += self.rDeltas[i]
def draw_level(self):
"""Draw the level background"""
self.screen.fill(WHITE)
class Spring:
def __init__(self, x, target_height, rod_width):
"""Spring Creator, one spring by one"""
self.x = x
self.y = 0
self.speed = 0
self.height = target_height
self.bottom = 400
self.rod_width = rod_width
def update(self, dampening, tension, target_height):
"""Update the springs, this is numerical integration
and called Euler Method, it is simple fast and usual"""
self.y = target_height - self.height
self.speed += tension * self.y - self.speed * dampening
self.height += self.speed
def draw(self, screen):
"""Draw the spring,
(Here this is a simple rod)"""
pygame.draw.line(screen, BLUE, (self.x, self.height), (self.x, self.bottom), self.rod_width)
class Counter_Waves_Motion(Thread):
def __init__(self, main):
Thread.__init__(self)
"""Thread init class, (counter class)"""
self.main = main
self.time = 0
self.max_time = 2
self.time_sleep = 0.01
self.done = False
def run(self):
"""Run the Thread, (parallel programming)"""
while not self.done:
self.main.update()
self.time += self.time_sleep
if self.time >= self.max_time:
self.done = True
time.sleep(self.time_sleep)
if __name__ == "__main__":
obj_main = Main()
## In this program all is OOP