So I'm making a PyGame that baseball is falling from up, and users in the bottom have to catch the ball. The balls are falling in a random speed, but I'm having hard time getting balls falling in different speed.
For example, my current code for the ball is:
def update(self):
if self.is_falling:
"""Move the ball down."""
self.y += random.randint(10, 200) / 100
self.rect.y = self.y
Here, when I run the program, the ball is falling in different speed but it's barely different. If I change the number to make it to (10, 20000) / 100 then every ball is dropping very fast. What would be the reason? Seems like random number is not so random. Am I using the function wrong?
I want to make each ball to drop in VERY different speed, such as one is very fast, and the other is very slow. And I would want it to be random number so that users can play with many different speed...
I wondered, if there is random function that I can set with a specific interval between generated random numbers? Or should I try a different approach? And if so, how should I do it?
I am very beginner at Python, so if you can explain it easy as possible, that will be much appreciated!
Use the rand function to draw the values from a uniform distribution in the open interval, (50,100). a = 50; b = 100; r = (b-a). *rand(1000,1) + a; Verify the values in r are within the specified range.
print(randint(1, 100)) # Pick a random number between 1 and 100. x = randint(1, 100) # Pick a random number between 1 and 100.
Use the random. sample() function when you want to choose multiple random items from a list without repetition or duplicates. There is a difference between choice() and choices() . The choices() was added in Python 3.6 to choose n elements from the list randomly, but this function can repeat items.
If this is Python 2 there is a problem with
random.randint(10, 200) / 100
because the division will be done in integer math. You should use
random.randint(10, 200) / 100.
Another problem is that you are choosing the random step at every update (probably every frame) and this will not give the illusion of a speed, but more of a randomly jerky movement. It would probably be better to choose a random speed like your are doing but keeping it the same at least for a few frames or even for the whole fall animation.
Part of the problem is sub-pixel distances. I think your main problem is your y
movement. Look at that equation for self.y +=
, half the time it will result in a pixel-distance of only a single pixel. When this is added to the self.rect, rounding (or truncation) will make less-than 1-pixel amounts disappear. For example, the random integer generated is 99, then divided by 100, is 0.99 of a pixel. In python int(0.99)
is zero. Thus around half of the time, the movement is zero, the other half, movement is only 1 pixel since int(150/100)
=> 1
. (One in every ~190 moments will be 2 pixels.)
def update(self):
if self.is_falling:
"""Move the ball down."""
self.y += random.randint(10, 200) / 100
self.rect.y = self.y
Also as @6502 points out, this will give a jerky random movement. It would be better to generate a pixels-per-update speed in the class __init__
, and stick with that.
def __init__( self, ... ):
...
self.fall_speed = random.randint(10, 200) # pixels per update
def update(self):
if self.is_falling:
"""Move the ball down."""
self.y += self.fall_speed
self.rect.y = self.y
I like to make things move based on real-time calculations. This takes the object speed, and the inter-frame timings to work out how much the object has moved. I like this because if you want to add gravity (or whatever) into the program, it's easy to calculate the new position.
class FallingSprite( pygame.sprite.Sprite ):
""" A falling sprite. Falls at a constant velocity in real-time """
def __init__( self, image ):
pygame.sprite.Sprite.__init__( self )
self.image = image
self.rect = self.image.get_rect()
self.fall_speed = random.randint(10, 200) # pixels / second
self.last_update = int( time.time() * 1000.0 )
self.rect.center = ( random.randrange( 0, WINDOW_WIDTH ), 0 )
def update( self ):
# There may have been movement since the last update
# so calculate the new position (if any)
if ( self.fall_speed > 0 ):
time_now = int( time.time() * 1000.0 )
time_change = time_now - self.last_update # How long since last update?
if ( time_change > 0 ):
distance_moved = time_change * self.fall_speed / 1000
now_x, now_y = self.rect.center # Where am I, right now
updated_y = now_y + distance_moved
# Did we fall off the bottom of the screen?
if ( updated_y > WINDOW_HEIGHT ):
# sprite disappears
self.kill()
else:
self.rect.center = ( now_x, updated_y )
self.last_update = time_now
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With