2
\$\begingroup\$

So my code works as intended, but suffers major performance issues every time I add a new object to the screen. The speed of my objects basically gets cut in half.

All you have to do to observe this is run the code and hit spacebar to create a new object. it is suppose to represent a production line. the product is the red square and the workstation is the green square.

The first station should take 5 seconds, The second station should take 8, and the third should be 3.

I'm guessing there is something fundamentally wrong with the way I am creating objects into the system that is leading to a slow run speed. Thoughts?

import pygame
import time


pygame.init()

screenx = 1200
screeny = 600

win = pygame.display.set_mode((screenx, screeny))

pygame.display.set_caption("simulation testing")

clock = pygame.time.Clock()


class Product(object):
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 5
        self.color = (255, 0, 0)
        self.count = 0

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

    def move(self):
        self.x += self.vel

    def wait(self):
        self.vel = 0

    def count_and_finish(self):
        global count
        count += 1


class Workstation(object):
    def __init__(self, name, x, y, width, height, cycletime):
        self.name = name
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.cycletime = cycletime
        self.color = (0, 255, 0)
        self.complete = False

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

    def do_work(self):
        global seconds
        if seconds <= self.cycletime:
            seconds += .1
            time.sleep(.1)
        else:
            self.complete = True
            seconds = 0


def redraw_screen():
    win.fill((0, 0, 0))
    pygame.draw.line(win, (255, 0, 0), (0, screeny // 2 + 155), (screenx, screeny // 2 + 155), 5)
    pygame.draw.line(win, (255, 0, 0), (0, screeny // 2 - 155), (screenx, screeny // 2 - 155), 5)
    ws1.draw(win)
    ws2.draw(win)
    ws3.draw(win)
    for product in products:
        product.draw(win)
    pygame.display.update()


seconds = 0
count = 0
products = []
ws1 = Workstation("ws1", 200, 165, 160, 165, 5)
ws2 = Workstation("ws2", 500, 165, 160, 165, 8)
ws3 = Workstation("ws3", 800, 165, 160, 165, 3)

run = True
while run:
    clock.tick(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        time.sleep(.25)
        products.append(Product(0, round(screeny // 2 - 75), 150, 150))

    for product in products:
        if product.x >= 0 and product.x + product.width + 15 <= screenx:
            if products.index(product) != 0:
                if product.x >= products[products.index(product) - 1].x - product.width - 10:
                    product.wait()
                elif product.x == ws1.x + 5:
                    product.wait()
                    ws1.do_work()
                    if ws1.complete:
                        product.vel = 5
                        ws1.complete = False
                        product.move()
                elif product.x == ws2.x + 5:
                    product.wait()
                    ws2.do_work()
                    if ws2.complete:
                        product.vel = 5
                        ws2.complete = False
                        product.move()
                elif product.x == ws3.x + 5:
                    product.wait()
                    ws3.do_work()
                    if ws3.complete:
                        product.vel = 5
                        ws3.complete = False
                        product.move()
                else:
                    product.vel = 5
                    product.move()
            else:
                if product.x == ws1.x + 5:
                    product.wait()
                    ws1.do_work()
                    if ws1.complete:
                        product.vel = 5
                        ws1.complete = False
                        product.move()
                elif product.x == ws2.x + 5:
                    product.wait()
                    ws2.do_work()
                    if ws2.complete:
                        product.vel = 5
                        ws2.complete = False
                        product.move()
                elif product.x == ws3.x + 5:
                    product.wait()
                    ws3.do_work()
                    if ws3.complete:
                        product.vel = 5
                        ws3.complete = False
                        product.move()
                else:
                    product.vel = 5
                    product.move()
        else:
            products.pop(products.index(product))
            product.count_and_finish()

    print(str(count))

    redraw_screen()

pygame.quit()
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Your Workstation objects are calling time.sleep(.1) when any object is being processed. This will delay the main loop. If more than one Workstation is active, the game will slow down twice as much.

If you want to sleep for 0.1 seconds, it should be done only by the main loop itself, after updating all of the items. It should never be done by the objects in the simulation.

\$\endgroup\$
1
\$\begingroup\$

AJ was right and I've been able to fix my code so that it performs as intended. I made the timer in the do_work() function part of the class instead. I was able to get the milliseconds per frame from the

clock = pygame.time.Clock()    # creates a clock object
self.seconds = clock.get_time()     # use the get time method that returns milliseconds per frame

self.seconds_total += seconds
if cycletime * 1000 <= seconds_total:    # Keeps track of the cycle time of the workstation to see if the product has been there long enough.

'

full code so people can see.

import pygame
import time


pygame.init()

screenx = 1200
screeny = 600

win = pygame.display.set_mode((screenx, screeny))

pygame.display.set_caption("simulation testing")

clock = pygame.time.Clock()


class Product(object):
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 5
        self.color = (255, 0, 0)
        self.count = 0

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

    def move(self):
        self.x += self.vel

    def wait(self):
        self.vel = 0

    def count_and_finish(self):
        global count
        count += 1


class Workstation(object):
    def __init__(self, name, x, y, width, height, cycletime):
        self.name = name
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.cycletime = cycletime
        self.color = (0, 255, 0)
        self.complete = False
        self.seconds = 0
        self.secondstotal = 0

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

    def do_work(self):
        self.seconds = clock.get_time() / 1000
        self.secondstotal += self.seconds
        if self.secondstotal >= self.cycletime:
            self.complete = True
            self.seconds = 0
            self.secondstotal = 0


def redraw_screen():
    win.fill((0, 0, 0))
    pygame.draw.line(win, (255, 0, 0), (0, screeny // 2 + 155), (screenx, screeny // 2 + 155), 5)
    pygame.draw.line(win, (255, 0, 0), (0, screeny // 2 - 155), (screenx, screeny // 2 - 155), 5)
    ws1.draw(win)
    ws2.draw(win)
    ws3.draw(win)
    for product in products:
        product.draw(win)
    win.blit(pygame.font.SysFont('None', 50).render('ws1 ' + str(round(ws1.cycletime - ws1.secondstotal, 2)), 0, (255, 255, 255)), (ws1.x, ws1.y - 55))
    win.blit(pygame.font.SysFont('None', 50).render('ws2 ' + str(round(ws2.cycletime - ws2.secondstotal, 2)), 0, (255, 255, 255)), (ws2.x, ws2.y - 55))
    win.blit(pygame.font.SysFont('None', 50).render('ws3 ' + str(round(ws3.cycletime - ws3.secondstotal, 2)), 0, (255, 255, 255)), (ws3.x, ws3.y - 55))
    win.blit(pygame.font.SysFont('None', 50).render('count ' + str(count), 0, (255, 255, 255)), (5, 5))
    pygame.display.update()


count = 0
products = []
ws1 = Workstation("ws1", 200, 165, 160, 165, 5)
ws2 = Workstation("ws2", 500, 165, 160, 165, 8)
ws3 = Workstation("ws3", 800, 165, 160, 165, 3)

run = True
while run:
    clock.tick(30)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        time.sleep(.25)
        products.append(Product(0, round(screeny // 2 - 75), 150, 150))

    for product in products:
        if product.x >= 0 and product.x + product.width + 15 <= screenx:
            if products.index(product) != 0:
                if product.x >= products[products.index(product) - 1].x - product.width - 10:
                    product.wait()
                elif product.x == ws1.x + 5:
                    product.wait()
                    ws1.do_work()
                    if ws1.complete:
                        product.vel = 5
                        ws1.complete = False
                        product.move()
                elif product.x == ws2.x + 5:
                    product.wait()
                    ws2.do_work()
                    if ws2.complete:
                        product.vel = 5
                        ws2.complete = False
                        product.move()
                elif product.x == ws3.x + 5:
                    product.wait()
                    ws3.do_work()
                    if ws3.complete:
                        product.vel = 5
                        ws3.complete = False
                        product.move()
                else:
                    product.vel = 5
                    product.move()
            else:
                if product.x == ws1.x + 5:
                    product.wait()
                    ws1.do_work()
                    if ws1.complete:
                        product.vel = 5
                        ws1.complete = False
                        product.move()
                elif product.x == ws2.x + 5:
                    product.wait()
                    ws2.do_work()
                    if ws2.complete:
                        product.vel = 5
                        ws2.complete = False
                        product.move()
                elif product.x == ws3.x + 5:
                    product.wait()
                    ws3.do_work()
                    if ws3.complete:
                        product.vel = 5
                        ws3.complete = False
                        product.move()
                else:
                    product.vel = 5
                    product.move()
        else:
            products.pop(products.index(product))
            product.count_and_finish()

    print(str(count))

    redraw_screen()

pygame.quit()
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.