I am using pygame to develop a train simulator (using simply a rect to represent a train) I have a class train and this class has a stop function to stop trains at each station (defined by an x coordinate):
def stop(self):
current_time = pg.time.get_ticks()
while pg.time.get_ticks() - current_time < self.stopping_Time:
continue
pass
This implementation works with one train instance but my problem is that when adding more trains, if an instance stop at its station all the other train instances stop even if they are not in there station!
I have tried this implementaion also and it didn't work:
def stop(self):
while self.stopping_Time> 0:
self.stopping_Time -= 1
pass
This answer didn't work for me also: https://stackoverflow.com/a/46801334/11334093
Is it a multithreading problem? do I need to create a thread for each train instance, so they can execute the stop function independently? Or how can I use a multiprocessing trick for this function?
Here is my whole train class:
class train(object):
"""docstring for train"""
def __init__(self, x, y, width, height, vel):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = vel
self.right = True
self.left = False
self.headway = 20
self.stopping_Time = 2500
self.capacity = 200
self.start_time = pg.time.get_ticks()
def draw(self, win):
#trains
pg.draw.rect(win, (255,0,0), (self.x, self.y, self.width, self.height))
def stop(self):
self.current_time = pg.time.get_ticks()
while pg.time.get_ticks() - self.current_time < self.stopping_Time:
continue
pass
def move(self):
if self.right:
if self.x == 235 or self.x == 510 or self.x == 1295:
self.stop()
if self.x == 1295:
self.right = False
self.left = True
self.x -= self.vel
else:
self.x += self.vel
else:
self.x += self.vel
else:
if self.x == 235 or self.x == 510:
#train.stop = 3 * 100
self.stop()
if self.x == 235:
self.right = True
self.left = False
self.x += self.vel
else:
self.x -= self.vel
else:
self.x -= self.vel
and I have another function which in it I call:
for train in op_trains:
train.move()
op_train is a list containing all train instances and it is filled by one train at a time.
I would strongly recommend against using multi-threading/processing for this problem of yours. While multi-threading/processing may be able to solve your problem, introducing it might make it hard to add to or improve the code in the future and will more than likely cause more bugs. This problem can be solved by just tweaking the design of the code.
The reason why all trains stop at once is due to the while loop in the stop function.
def stop(self):
current_time = pg.time.get_ticks()
while pg.time.get_ticks() - current_time < self.stopping_Time:
continue
pass
This while loop blocks the main thread, preventing pygame from processing other trains. The stop function is called from the move function within the train class. The goal now is to replace this while loop with a way to keep track of how long to keep the train stopped that does not block the main thread.
What you need to do is to have a state in your train class to represent whether or not the train is stopped or not.
def __init__(self, x, y, width, height, vel):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = vel
self.right = True
self.left = False
self.headway = 20
self.stopping_Time = 2500
self.capacity = 200
self.start_time = pg.time.get_ticks()
# new attributes
self.stopped = False
self.stopped_time = None
To stop the train, toggle the state and record down the time the stop started.
def stop(self):
self.stopped_time = pg.time.get_ticks()
self.stopped = True
In your move function, have an if condition to check if this flag is True and if it is, how long has it been stopped. If it has stopped for long enough, set the flag to False and move on. I have went ahead and reordered the function as well as cleaned up the conditions as well.
def move(self):
if self.stopped and pg.time.get_ticks() - self.stopped_time < self.stopping_Time:
return
self.stopped = False
if self.right:
self.x += self.vel
else:
self.x -= self.vel
if self.x == 235 or self.x == 510 or self.x == 1295:
self.stop()
if self.x == 235:
self.right = True
self.left = False
elif self.x == 1295:
self.right = False
self.left = True
Notice that there are no loops.
This code assumes that your calls to train.move()
is in a main event loop of some sort where it is continuously being called.