Raidez
Raidez

Reputation: 13

Calculation speed with property into class

I'm french so pardon my language error.

I try to make a little pygame-zero game with ball physic. So I want to control precisely a ball object in time.

I created a Ball's class, which implement built-in Rect object (to use default collision in case).

import pygame

WIDTH = 300
HEIGHT = 300

class Color:
    WHITE = (255, 255, 255)
    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)

class Ball(pygame.Rect):
    def __init__(self, cx, cy, radius, color: Color = Color.WHITE):
        position = (cx - radius, cy - radius)
        size = (radius * 2, radius * 2)
        super(Ball, self).__init__(position, size)
        self.radius = radius
        self.color = color

    @property
    def cx(self):
        return self.x + self.radius

    @cx.setter
    def cx(self, cx):
        self.x = cx - self.radius

    @property
    def cy(self):
        return self.y + self.radius

    @cy.setter
    def cy(self, cy):
        self.y = cy - self.radius


    def draw(self):
        position = (self.cx, self.cy)
        screen.draw.filled_circle(position, self.radius, self.color);
        # screen.draw.rect(self, Color.RED) # draw hitbox

I instance a ball object and want make it go at x position 0 to 300. (the width of the window).

I use the default delta time (it's the time in millisecond elapsed between each frame 1/60) in update's function.

With a speed of 100 pixel * delta time, the ball will traverse the screen at 3 seconds (logical).

But it's not ... after some manipulation I created a second ball (I switch ball's name) and when I use variable instead all works fine.

cl = 0 # get time elpased at launch
ball = Ball(0, 10, 10, Color.RED)
x = ball.cx
ball2 = Ball(0, 30, 10, Color.BLUE)
speed = 100

def draw():
    screen.clear()
    ball.draw()
    ball2.draw()
    screen.draw.text(f"{cl:7.2f}", (0, 150))

def update(dt):
    global cl, x
    if ball.cx <= WIDTH:
        cl += dt

        # the ball make 3 seconds exactly
        x += speed * dt
        ball.cx = x

        ball2.cx += speed * dt # don't make 3 seconds WHY ?

My question ... why ? Create a custom property, it's much slower than classic variable definition ?

Upvotes: 1

Views: 90

Answers (1)

Rabbid76
Rabbid76

Reputation: 210947

If you want to ensure time precise calculations, then you've to do all the calculations with floating point values. Only convert the coordinates to integral data types when drawing the objects on is integer pixel position.

The .cx property has an integral data type. Every time when the position is incremented, then the fraction part of the number which is added is lost. This causes an increasing inaccuracy. The object appears to be slower than expected. Note, if the frame rate would be higher, then the object will even stand still, if the step per frame is smaller than 1.0. The integer part of a value < 1.0 is 0.

Note

ball2.cx += speed * dt

does the same as

ball2.cx += int(speed * dt)

The x variable is a floating point value. It is incremented with full accuracy. The exact value is cast to int when it is assigned to the .cx property, but the inaccuracy is always smaller than 1.0 and thus almost negligible.

x += speed * dt
ball.cx = x  

does the same as

x += speed * dt
ball.cx = int(x) 

Upvotes: 1

Related Questions