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()
2 Answers 2
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.
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()
Explore related questions
See similar questions with these tags.