I'm wondering how to speed up the smoothness of my code written in Python using pygam. I'm guessing I have to make this more efficient somehow? When this is run, some balls move around randomly in a set area, however, the new position of each ball is not smooth at all, there is a jump between each movement as the cycle is very slow. How do I fix this? Or is there any suggestions on how to improve it? This is my code so far:
import pygame
from pygame import *
import random
pygame.init()
size = width, height = 800, 600
screen = display.set_mode(size)
pygame.display.set_caption("Year 12: Ideal Gas Simulation")
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
WHITE=(255,255,255)
GREEN = (0, 255, 0)
BALLX = 0
BALLY = 1
BALLSPEEDX = 2
BALLSPEEDY = 3
List=[]
radius=5
running=True
myClock=time.Clock()
myClock.tick(60)
def initBall():
for n in range(40):
ballx = random.randint(0, 800) # randomly setting the x position
bally = random.randint(0, 600) # randomly setting the y position
dirx = random.randint(-5,5) # randomly setting the x speed
diry = random.randint(-5,5) # randomly setting the y speed
data=[ballx, bally, dirx, diry]
List.append(data)
# returning a list with all the data the ball needs
return List # returning the list
def drawScreen(List):
draw.rect(screen, WHITE, (0, 0, 800, 600))
for x in range(40):
BALLX=List[x][0]
BALLY=List[x][1]
draw.circle(screen, GREEN, (BALLX,BALLY),radius)
display.flip()
pygame.draw.rect(screen, BLACK, (100-radius,100-radius,600+(2*radius),400+(2*radius)), 1)
f=pygame.font.SysFont(None,60)
text=f.render("PV=nRT",True,(0,0,0))
screen.blit(text,(300,height/20))
def moveBall(List):
for x in range(40):
BALLX=List[x][0]
BALLY=List[x][1]
SPEEDX=List[x][2]#####data[BALLX]== the first index of each list [x][0]
SPEEDY=List[x][3]##data[BALLSPEEDX]= List[x][2]
age=SPEEDX+BALLX
List[x][0]=age
# increases the position of the ball
plus=SPEEDY+BALLY
List[x][1]=plus
# checks to see if the ball is hitting the walls in the x direction
if BALLX > 700:
List[x][0] = 700#NORMALLY 800
third=List[x][2]
answer=third*-1
List[x][2]=answer
elif BALLX < 100:#NORMALLY 0
List[x][0] = 100
third=List[x][2]
answer=third*-1
List[x][2]=answer
# checks to see if the ball is hitting the walls in the y direction
if BALLY < 100:
List[x][1] = 100#NORMALLY 0
third=List[x][3]
answer=third*-1
List[x][3]=answer
elif BALLY > 500:
List[x][1] = 500#NORMALLY 600
third=List[x][3]
answer=third*-1
List[x][3]=answer
return List#return updated list
List=initBall()
while running==True:
for evnt in event.get():
if evnt.type==QUIT:
running=False
quit()
if evnt.type==MOUSEBUTTONDOWN:
mx,my=evnt.pos
button=evnt.button
drawScreen(List)
List=moveBall(List)
In addition to skrx's answer, you can also refactor the code and avoid a lot of duplicate calls. Also, indexing the BALLS
array directly might improve performance slightly.
Generally, avoid naming variables inside functions with uppercase. These names are typically given to constants defined at the top of your file.
The version I came up with is below:
import array
import pygame
pygame.init()
import random
from pygame import *
size = WIDTH, HEIGHT = 800, 600
screen = display.set_mode(size)
pygame.display.set_caption("Year 12: Ideal Gas Simulation")
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
WHITE = (255,255,255)
GREEN = (0, 255, 0)
BALLX = 0
BALLY = 1
BALLSPEEDX = 2
BALLSPEEDY = 3
RADIUS = 5
BALLS = []
myClock = time.Clock()
myClock.tick(60)
def initBalls():
for n in range(40):
props = array.array('i', [
random.randint(0, WIDTH),
random.randint(0, HEIGHT),
random.randint(-5, 5),
random.randint(-5, 5),
])
BALLS.append(props)
def drawScreen():
draw.rect(screen, WHITE, (0, 0, 800, 600))
props = (100-RADIUS, 100-RADIUS, 600+(2*RADIUS), 400+(2*RADIUS))
pygame.draw.rect(screen, BLACK, props, 1)
f = pygame.font.SysFont(None, 60)
text = f.render("PV=nRT", True,(0, 0, 0))
screen.blit(text,(300, HEIGHT / 20))
for i in range(len(BALLS)):
draw.circle(screen, GREEN, BALLS[i][:2],RADIUS)
display.flip()
def moveBalls():
for i in range(len(BALLS)):
if BALLS[i][0] > 700:
BALLS[i][0] = 700
BALLS[i][2] *= -1
elif BALLS[i][0] < 100:
BALLS[i][0] = 100
BALLS[i][2] *= -1
else:
BALLS[i][0] += BALLS[i][2]
if BALLS[i][1] < 100:
BALLS[i][1] = 100
BALLS[i][3] *= -1
elif BALLS[i][1] > 500:
BALLS[i][1] = 500
BALLS[i][3] *= -1
else:
BALLS[i][1] += BALLS[i][3]
def main():
initBalls()
while True:
for evnt in event.get():
if evnt.type == QUIT:
pygame.quit()
return
elif evnt.type == MOUSEBUTTONDOWN:
mx, my = evnt.pos
button = evnt.button
drawScreen()
moveBalls()
if __name__ == "__main__":
main()