2

I am working on a simulation that represents a production line with moving products.

My calculations of the arrival time from the products at a certain (x,y) on paper does not match the calculations of my simulation.

My iteration time of my pygame while loop takes 0.01 second with a very small uncertainty.

So my pixel movement is 0.5 and the length is, for example, 645 pixels. So I thought every step is 0.5 pixel and this will take 1290 steps in total. With an iteration time of 0.01 second this should have a duration of 12,9 second.

However, my simulation needs 16 seconds for a length of 645 pixels.

Can someone explain the difference ?

I made an piece of code with only one RECT so the iteration time is faster but there is still a difference

EXAMPLE :

import pygame, sys, time, random
init_time = time.time()
from pygame.locals import *



pygame.init()

w_x = 1550
w_y = 800

DISPLAYSURF = pygame.display.set_mode((w_x,w_y))
pygame.display.set_caption('COPAL')

## COLORS USED (SIZE CORRESPONDS TO COLOR)
# background
BLACK = (0,0,0)

# boxes
GREEN = (0,100,0)
PINK = (255,0,255)
BLUE = (0,0,128)

xx = 0
yy = 400

but_on = True
sum_duration = 0
total_iteration = 0

total = []



box = [[xx,yy]]

## Filling background
DISPLAYSURF.fill(BLACK)
start = time.time()

start2 = time.time()


while True:


    init_end = time.time()


    if but_on == True:
        print(init_end-init_time)
        but_on = False    


    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()



    DISPLAYSURF.fill(BLACK)

    pygame.draw.rect(DISPLAYSURF,BLUE,(xx,yy,30,30))


    pygame.draw.line(DISPLAYSURF,PINK,(645,0),(645,800))

    xx += 0.5

    if xx == 645:

        timex = time.time()
        print(timex - start2)

        print(time_iteration_avg)


    stop = time.time()

    duration = stop - init_end

    total.append(duration)

    sum_duration += duration

    time_iteration_avg = sum_duration / len ( total )




   pygame.display.update()

EXAMPLE EDITED

import pygame, sys, time, random
init_time = time.time()
from pygame.locals import *



pygame.init()

# window aize
w_x = 1550
w_y = 800

# time for each step
ite = 0.00387

DISPLAYSURF = pygame.display.set_mode((w_x,w_y))
pygame.display.set_caption('COPAL')


# background
BLACK = (0,0,0)

# boxes
GREEN = (0,100,0)
PINK = (255,0,255)
BLUE = (0,0,128)

# start position
xx = 0
yy = 400

but_on = True
sum_duration = 0
total_iteration = 0

total = []

oo= 0

step = 0.5

duration = ite

box = [[xx,yy]]

## Filling background
DISPLAYSURF.fill(BLACK)
start = time.time()

start2 = time.time()


while True:


    init_end = time.time()


    if but_on == True:
        init_t = (init_end - init_time)

        print(init_t)
        but_on = False    


    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()



    DISPLAYSURF.fill(BLACK)

    pygame.draw.rect(DISPLAYSURF,BLUE,(xx,yy,30,30))


    pygame.draw.line(DISPLAYSURF,PINK,(645,0),(645,800))

    xx += step

    if round(xx) == 645:

        timex = time.time()
        print("elapsed time ")
        print(timex - start2)

        print(time_iteration_avg)




    if duration == ite:

        step = 0.5



    if duration < ite:
        dif_ite = ite - duration
        time.sleep(dif_ite)

        print("Smaller")

        step = 0.5

    if duration > ite:
        dif_pix = duration - ite

        pix_ex = 5 / duration

        step = 645 / pix_ex

        print("Bigger")

    total.append(duration)

    sum_duration += duration

    time_iteration_avg = sum_duration / len ( total )


    print(step)


    stop = time.time()
    duration = stop - init_end


    pygame.display.update()
ninja
  • 55
  • 1
  • 1
  • 6
  • 1
    Could it be that some loop iterations are taking slightly longer, creating an unexpectedly long runtime? https://stackoverflow.com/questions/24039804/pygame-current-time-millis-and-delta-time Try using delta based loops to have a set time per frame/loop iteration – clubby789 Oct 09 '19 at 08:10
  • How is your loop constructed? In your loop do you use pygame's clock.tick, or time.sleep, or you use something else, or there is nothing specific for sleeping and its just that you think your code taking 0.01 seconds to complete an iteration? – unlut Oct 09 '19 at 08:13
  • My setting of my while loop is 1 mili second (using: time.wait(1). However when I check this with the time.clock function I can see that after every iteration 0.01 second is passed and this value has very low fluctuations. – ninja Oct 09 '19 at 08:17
  • 1
    I am not sure what exactly is "time.wait", but if that is sleeping your program for 1 milisecond at each iteration you are waiting for (1 milisecond + amount of time your code needs to execute). – unlut Oct 09 '19 at 08:21
  • I deleted the time.wait so the only thing that is left is the while True: In this situation I still have a difference of 1.3 second – ninja Oct 09 '19 at 08:51
  • You shoud [edit](https://stackoverflow.com/posts/58299617/edit) your question and show the code so we can better understand how you are timing the code – Valentino Oct 09 '19 at 10:14

1 Answers1

2

Jammy Dodger already pointed out the main issue, but I will try to explain further.
When you code a game (or any physics simulation really), you can not rely on the fact that your code piece will always take same amount of time to execute. It is possible that:
1- You tried to suspend your application (via sleep), but OS may not resume your program's execution at the exact time you specified. I would say this is the main reason.
2- You tried to draw something to screen/GPU/RAMbuffer, working speed of the device may not be same for each of your requests.
3- Probably dozens of more reason that I can not think of right now.

Correct thing to do is the measure amount of elapsed time between frames, and adjust your physics simulation (eg:speed of your box in your code) accordingly. Read the comments near xx += ... part. (Some people may criticize the code due to usage of time.sleep instead of pygame's clock.tick, but I am just trying to make it easy to understand):

import pygame, sys, time, random
init_time = time.time()
from pygame.locals import *


#  frame per second you want
FPS = 100

#  speed at each frame
SPEED = 0.5

#  use a pygame clock object to control FPS
#clock = pygame.time.Clock()





pygame.init()

w_x = 1550
w_y = 800

DISPLAYSURF = pygame.display.set_mode((w_x,w_y))
pygame.display.set_caption('COPAL')

## COLORS USED (SIZE CORRESPONDS TO COLOR)
# background
BLACK = (0,0,0)

# boxes
GREEN = (0,100,0)
PINK = (255,0,255)
BLUE = (0,0,128)

xx = 0
yy = 400

but_on = True
sum_duration = 0
total_iteration = 0

total = []



box = [[xx,yy]]

## Filling background
DISPLAYSURF.fill(BLACK)
start = time.time()

start2 = time.time()


#  initial value
time_spend_py = 1 / FPS

elapsed_step = 0
while True:
    init_end = time.time()
    loop_start_time = time.time()

    if but_on == True:
        print(init_end-init_time)
        but_on = False    

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    DISPLAYSURF.fill(BLACK)

    pygame.draw.rect(DISPLAYSURF,BLUE,(xx,yy,30,30))


    pygame.draw.line(DISPLAYSURF,PINK,(645,0),(645,800))


    #  amount of change depends on elapsed time since last frame!
    #  Example:
    #  FPS: 100, time_spend=0.012 s
    #  your loop took more time at last iteration
    #  because of that we need to adjust speed
    #  xx += SPEED * (0.012 / (1/100))
    #  xx += SPEED * (0.012 / 0.010)
    #  xx += SPEED * 1.2
    #  so object moves faster
    xx += SPEED * (time_spend_py / (1 / FPS))    

    if xx >= 645:

        timex = time.time()
        print(timex - start2)

        print(time_iteration_avg)
        print("Elapsed step:{}".format(elapsed_step))
        exit(0)


    pygame.display.update()

    stop = time.time()
    duration = stop - init_end
    total.append(duration)
    sum_duration += duration
    time_iteration_avg = sum_duration / len ( total )

    #time_spend = clock.tick(FPS)
    time.sleep(0.01)
    elapsed_step += 1
    loop_end_time = time.time()
    time_spend_py = loop_end_time - loop_start_time
unlut
  • 3,525
  • 2
  • 14
  • 23
  • @ninja Make sure to mark this answer if it helped you with the question, so other people will know that the question is solved and to give the poster reputation points. – Ted Klein Bergman Oct 09 '19 at 21:16
  • Helllo. I did what you advised me. However, I have still a delay of 0.9 seconds and I can not find the problem. I calculated that 645 pixels in steps of 0.5 is 1290 steps. So if the box have to displace in 5 seconds every iteration has to be 0.00387 seconds. – ninja Oct 15 '19 at 07:34
  • @ninja Because it seems you still do not understand the main source of the problem (at least that is what I get from reading your code). You are expecting time.sleep command to stop execution of the program for exact amount you specified for, but it will not. Your "time.sleep(dif_ite)" will not exactly last for dif_ite amount of seconds. Instead of trying to make each iteration of loop take same time, you must accept the fact that differences can happen and adjust object speed accordingly. Also you are not considering the time it takes for pygame.display.update(). – unlut Oct 15 '19 at 09:59
  • @ninja Please look at this example here: https://pastebin.com/uCwGWTCr , especially two important parts: 1- CONSTANTS section, 2- Deciding step value at each iteration – unlut Oct 15 '19 at 10:01
  • thank you for your comment, but the example does not exist anymore. – ninja Oct 28 '19 at 08:44
  • thank you. my simulaion has a time difference of 0.4 seconds now. – ninja Oct 28 '19 at 11:21
  • I think it shouldn't be that large for a short simulation. Make sure you include things like pygame.display.update() and print during calculation of frame time. – unlut Oct 28 '19 at 11:35
  • yes i did. my simulation has 800 lines of code, what i put online was just an example of my simulation. I generate 4 boxes and they have a speed of 0.5 m/s. the boxes have no space between them. At a certain (x,y) they get a speed of 0.6 m/s this will cause a space between the boxes. if you calculate the length of the space this should be 3 cm. However the simulation makes spaces of 7.4 cm. Do you know how this is possible? – ninja Oct 29 '19 at 07:19
  • First thing I could advise is if you need more precision, use pygame's clock mechanism instead of time.sleep then check your results after that change. – unlut Oct 31 '19 at 10:15
  • But in my opinion it is hard to give a good advice without seeing your work because two things you want (1- Expecting your calculated time on paper to be equal to your simulation program's execution time, 2- Accurate physics such that your space being 7.4 instead of 3) are hard to satisfy together. – unlut Oct 31 '19 at 10:21