0

This is a small part of some more complicated code but basically. I've narrowed down the problem to this one bit of code.

I'm using the formula s = ut + 1/2 at^2 to get the distance traveled in one instance to time, in this case, 0.001 seconds which will then further be used to draw the rects on a window.

import pygame


run = True
clock = pygame.time.Clock()

ex_s = pygame.Rect((500, 625, 50, 50))
start_height = ex_s.top
print(start_height, "m")

g = -9.8
v = 400
t = 0.001
while run:

    ex_s.top -= (v * t) + ((g / 2) * (t ** 2))

    print(ex_s.top - start_height)

    if (ex_s.top - start_height) * -1 <= -10:
        run = False
    clock.tick(30)

I want the rectangles to move upwards/downwards based on their velocity.

The rectangles move up and get stuck whenever the top reaches y = 0. This doesn't happen if the value of "t" is increased to o.o1 or above but I need it to be 0.001 for the precision. The problem is also solved when the value of v is increased by an order of magnitude, changing g does nothing.

I tried using both move and move_ip and the y coordinate did not change at all.

I've also tried manually pushing the objects above y = 0 when they hit it but it doesn't do anything. The fact that the problem changes with decimal places has led me to believe it could be something to do with the integer coordinate system of pygame but I don't see how this would cause things to move first and then get stuck only at 0.

2 Answers2

1

See Pygame doesn't let me use float for rect.move, but I need it. The problem is that a pygame.Rect object can only store integer data. So when you add a value less than 1.0 to the coordinate of a rectangle, than the position stays the same. You need to store the position of the rectangle in separate variables and update the position of the rectangle using these variables.

ex_s = pygame.Rect((500, 625, 50, 50))
ex_s_y = ex_s.top

# [...]

while run:
    # [...]

    # change position
    ex_s_y = .....

    ex_s.top = round(ex_s_y)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Yeah, I figured it was something to do with the objects but why would it cause no issues below zero? Could it be that at non-zero values pygame rounds as ceiling while at zero it does floor? Thanks for answering! – BlueCheese Dec 18 '22 at 11:17
  • @BlueCheese You didn't read the linked answer. The result is truncated. e.g. 5 + 0.5 = 5, but 5 - 0.5 = 4. – Rabbid76 Dec 18 '22 at 11:24
1

You didn't change the time t variable, and your formula for the motion is wrong. Also your initial time, initial velocity and g are wrong.

If you want to use an exact solution for the position, do like this.

dt = 0.05
t = 0
g = 9.8 # It's positive by definition.
v = -100 # It's upward.
while run:
    y = 625 + v*t + 0.5*g*t**2 # The acceleration is +g, downward.
    t += dt
    ex_s.top = y
    ...

If you want to solve the equation of motion approximately and iteratively, do like this inside the loop.

...
y = 625
while run:
    v += g * dt
    y += v * dt
    t += dt
    ex_s.top = y
    ...

The above method is called sympletic Euler method. There're other more accurate methods, such as Runge-Kutta method.

relent95
  • 3,703
  • 1
  • 14
  • 17
  • Thanks a lot! this worked out pretty well. I used the basic formula for motion but I probably shouldn't have in this case. Also, t doesn't need to change every iteration since we're incrementing the velocity and distance as you've done in the Euler method example. – BlueCheese Dec 18 '22 at 11:14
  • No, the method is called semi-explicit or symplectic Euler method. For mechanical problems it is, in some criteria, better than the pure Euler method (where the unchanged velocity is used for the position update). – Lutz Lehmann Dec 19 '22 at 21:15
  • Yes, Lutz is right. I corrected the name. – relent95 Dec 20 '22 at 01:01