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()
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jan 24, 2019 at 23:56
\$\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.

answered Jan 25, 2019 at 23:11
\$\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()
answered Jan 28, 2019 at 2:39
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.