1

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.

BAKYAC
  • 155
  • 2
  • 12
  • It is unlikely for this to be a multi-threading/processing issue. Nevertheless, we will need more information from you. Kindly post the implementation of your Train class as well as how you are calling the stop function. – wxker May 11 '20 at 10:50
  • I tried that: `pool = multiprocessing.Pool(mp.cpu_count()) pool.map(train.move, [train for train in op_trains]) pool.close()` but it doesn't work! – BAKYAC May 11 '20 at 11:21

1 Answers1

2

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.

wxker
  • 1,841
  • 1
  • 6
  • 16
  • Thank you so much for your help, I have been messing around with threads and multiprocessings ... and none of these worked for me! Thank you again it works like a charm. – BAKYAC May 11 '20 at 17:30