1
  • Say you move your object Upwards (0-degrees) that would be move_ip((1, 0))
  • or to the right 90-degrees (0, 1)
  • then 45-degrees would be (1, 1). You get my point.

But how would I move it, say 22 degrees? Math wise that would be around (0.5, 0.75) (not exactly accurate, but a float value is my point). Now how do I move_ip my unit to (0.5, 0.75)? You can't, because PyGame only moves in full integers, not floats. So the only solution you have is to make the value bigger, with for example (0.5 * 100, 0.75 * 100) so (50, 75). But this doesn't work because now my block is moving way too far/fast so it ends up jumping "through" walls and other objects. Sure I can just do * 2 or so, but you just end up with a smaller increment of the same "moving too fast" problem.

So how can I move character 10-degrees, but one-ish unit away (not 100 units away). I am using degrees, so a solution like move_degrees(degree=10, distance=1) would also be fine.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Frank
  • 2,109
  • 7
  • 25
  • 48
  • 22 degrees in north-clockwise convention would be (0.37, 0.93) (calculated as `(math.sin(22 * math.pi/180), math.cos(22 * math.pi/180))` in python) – Stef Sep 24 '21 at 09:33

1 Answers1

1

how do I move_ip my unit to (0.5, 0.75)

You can not.

Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.

The coordinates for Rect objects are all integers. [...]

The fraction part of the coordinates gets lost when the new position of the object is assigned to the Rect object. If this is done every frame, the position error will accumulate over time.

If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location (e.g. .topleft) of the rectangle:

x += 0.5
y += 0.75
rect.topleft = round(x), round(y)

Minimal example:

replit.com live example PyGame-move-one-unit-in-degrees

import pygame

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
x, y = 200, 200
rect = pygame.Rect(0, 0, 20, 20)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False          

    x = (x + 0.5) % 400
    y = (y + 0.75) % 400
    rect.center = round(x), round(y)

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), rect)
    pygame.display.flip()
    clock.tick(100)

pygame.quit()
exit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Great answer; emphasis on storing the precise floating-point values, and only rounding when displaying on screen, to avoid accumulation of error over time. – Stef Sep 24 '21 at 09:35
  • 1
    @Stef Usually the `pygame.Rect` object is also used for collision detection. (See [How do I detect collision in pygame?](https://stackoverflow.com/questions/29640685/how-do-i-detect-collision-in-pygame/65064907#65064907)). I recommend keeping it up to date. In general, the object is moved and drawn once per frame. – Rabbid76 Sep 24 '21 at 09:44
  • 1
    Right right right. Sorry. Emphasis on only rounding when updating pygame.Rect, and not using the rounded value to perform further movement calculations. – Stef Sep 24 '21 at 09:57