简体   繁体   中英

Python choose random number in specific interval

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!

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM