Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 856
Sarah Avatar asked Feb 22 '19 20:02

Sarah


People also ask

How do you generate a random number in an interval?

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.

How do you randomly pick a number between 1 and 100 in Python?

print(randint(1, 100)) # Pick a random number between 1 and 100. x = randint(1, 100) # Pick a random number between 1 and 100.

How do you generate random choices in Python?

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.


2 Answers

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.

like image 196
6502 Avatar answered Oct 17 '22 03:10

6502


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
like image 41
Kingsley Avatar answered Oct 17 '22 03:10

Kingsley