Reputation: 191
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!
Upvotes: 6
Views: 1207
Reputation: 70
Just tweak the numbers a bit, 20000 is an awfully large jump from 200. As the values you are getting now are 10/100 and 200/100. Which is .1 to 2 pixels, so I don't imagine they would be very different.You jumped to 10/100 to 20000/100, which is a massive speed which is about 200 pixels cap vs the original 2. So that's your issue. Perhaps a range like 200 to 2000 or even 200 to 2500. You don't need such a large tweak as you said the balls began to fall very quickly. I've made the same kind of game before, and I can say that you just need to tweak the numbers slightly.
Upvotes: 0
Reputation: 14906
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
Upvotes: 1
Reputation: 114481
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.
Upvotes: 2