BGE: Random Numbers

There will come a time in any game where you’ll want to introduce a bit of randomness into it to stop sequences becoming predictable. This tutorial will introduce how we can get random numbers in python and return to our Duck Duck Moose game example to see them in action.

We can create random numbers using the BGE’s random actuator and the generated numbers are copied to an object’s property (you can read more about this here). However, this isn’t always useful when you want a random number in a script such as a throw-away local variable with a random value. This is where random.py come in. So lets have a look:

import random

x = random.random()
print(x)

x = random.uniform(0, 2)
print(x)

x = random.randrange(1, 100, 2)
print(x)

x = random.randint(1, 10)
print(x)

myList = ['apple', 'orange', 'bananna', 'grape']
x = random.choice(myList)
print(x)

random.shuffle(myList)
print(myList)

The first step to getting random numbers is to import random.py and then we can start using the various functions contained within. Let’s take each one in turn.

random.random() forms the basis for most the other functions in random.py. It returns a floating point number within the semi open range of 0.0 to 1. This means that it’ll generate 0.0 but will not produce 1.

random.uniform(a,b) returns a floating point number within the range specified (where a <= N <= b).

random.randrange(start, stop, step) produces an integer within the selected range (but doesn’t actually build a range object). We can specify a step value, so in the above example x will only be even values since we’re stepping through the range in twos.

random.randint(a,b) returns a random integer within the given range (where a <= N <= b).

random.choice(sequence) provides with a random selection from within a given sequence. In our example we used a list, but this could just as easily be a string, in which case, we’d get an individual character.

random.shuffle(sequence) shuffles sequences in place, bit like a deck of cards.

And that’s pretty much all there is to getting and using randomisation in python. There are other methods contained in random.py for various other random bits and bobs, but for our purposes the methods listed above are probably going to be enough. If they’re not, check the python random.py documentation.

A note on randomness

The numbers generated aren’t actually truly random numbers, they’re pseudo-random numbers created by a pseudo-random number generator (PRNG). When imported, random.py starts with a number (know as a seed) and performs a series of calculations on it to produce the final result. There are a number of different ways to calculate pseudo-random numbers, python uses the Mersenne Twister methodThe result of the calculation is then used to seed the next pseudo-random number. This means that the random numbers generated is entirely deterministic and is not safe for cryptographic purposes.

Where the initial seed comes from will largely be based on the operating system. Different OS’s have different methods of generating more secure random numbers by mixing together sources from the physical world (since this is non-deterministic). This can be things like keystrokes, mouse movements, hard drive access and incoming Ethernet packets. This results in a seed that is unpredictable and highly unlikely to be repeated. If there are no OS methods available to python then the system time is used.

We can deliberately seed the generator by calling random.seed() and passing it any hashable object, like a number. So, calling random.seed(254) at the beginning the script will produce the same set of random numbers each time it is run since the seed is always the same. This is useful for testing purposes, or when you want something to appear random that is actually not.

All duck and no moose

Let’s use our new random numbers to finally introduce the moose and randomise the sequence of spawned creatures. Check out spawn.py:

import random
import bge

cont = bge.logic.getCurrentController()
own = cont.owner

delay = own.sensors['Delay']
spawn = own.actuators['AddObject']

spawn.object = random.choice(['DuckieLow', 'BlueDuckieLow', 'MooseLow'])
spawn.instantAddObject()

obj = spawn.objectLastCreated
x = random.uniform(0.07, 0.04)
obj.actuators['Motion'].dLoc = [x,0,0]

delay.delay = random.randint(20,60)

We’re using random.choice() to provide a selection from a list of various objects that can be spawned by the game. We’re then using the object actuators .objectLastCreated attribute to get that object and vary the speed at which it moves at using random.uniform() to return a float for us to use. Finally, we vary the delay sensor triggering each spawning the objects using random.randint().

But we can do better than that. What if wanted mainly yellow ducks spawned, with moose’s being less likely and blue ducks being even rarer? Well, we could do this:

spawn.object = random.choice(['DuckieLow', 'DuckieLow','DuckieLow', 'BlueDuckieLow', 'MooseLow', 'MooseLow'])

Alternatively, we could use a series of if statements with a randomly generated integer, similar to switch-case statements in C++. So spawn.py could look like this:

import random
import bge

cont = bge.logic.getCurrentController()
own = cont.owner

delay = own.sensors['Delay']
spawn = own.actuators['AddObject']

i = random.randint(0, 10)

if i == 10:
    spawn.object = 'BlueDuckieLow'
elif i < 10 and i > 6:
    spawn.object = 'MooseLow'
else:
    spawn.object = 'DuckieLow'

spawn.instantAddObject()

obj = spawn.objectLastCreated
x = random.uniform(0.04, 0.07)
obj.actuators['Motion'].dLoc = [x,0,0]

delay.delay = random.randint(20,60)

 Parting words

The random module is great! It’s simple to use and I can’t think of a game project where I’ve not used it for one thing or another. I’m a big fan of using it in AI applications to give enemies a sense of unpredictability. I’ve also used it when generating enemies to create a bit of uniqueness to them, such as randomly distributing left and right handed enemies, enemies that move at differing speeds and have varying accuracy and weapons. There are lots of different random methods contained within random.py, but I’ve only ever had cause to use random.randint(), random.uniform() and random.choice() in my games. It’s worth noting that there is no random bool. But can always use random.choice([True, False]) or random.randint(0,1) to achieve this.

As per usual, if you have any questions or comments drop them below.

Resources

Duck Duck Moose game

 

Advertisements

~ by Jay on May 10, 2014.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: