This is a continuation from Part 2

Velocity/Movement:

Whilst we can move our ‘player’ we will need to make things interesting the computer will probably need to move things as well.

To do this we will add some code to give the particles a random velocity. Velocity consists of a direction and a speed (as it is a vector quantity). We will add variables for these in the Particle class:

def __init__(self, (x,y), size):
self.x = x;
self.y = y;
self.size = size;
self.colour = (255, 0, 0);
self.thickness = 1;
self.speed = 0.03
self.angle = random.uniform(0, math.pi*2)

If we run the code now, nothing different will happen as we have not updated the particle’s position.

To find out how far the a particle has moved we will break the velocity vector down into its x and y components. This is easy using simple trig:

v_x = speed * cos(angle)

v_y = speed * sin(angle)

dx and dy are then the integral of these:

integral(v)dt

We can assume dt is 1 and just add v_x and v_y to the x and y coordinates each main loop iteration:

self.x += math.cos(self.angle) * self.speed
self.y += math.sin(self.angle) * self.speed

However, since the +ve y direction is actually the downward direction we need to use a -ve to invert the y amount. We will also put the code into the class:

def move(self):
self.x += math.cos(self.angle) * self.speed
self.y -= math.sin(self.angle) * self.speed

We can then call move() before we call display() in the particle loop:

for particle in particles:
particle.move();
particle.display();

The particles should now all move out of the display window in random directions at a constant speed.

Bounding Boxes:

We can check if the particle has reached the edge of the window by checking the following boundaries:

if x > screen_w:

#Bottom of screen

elif x < 0:

#Top of screen

if y > screen_h:

#Right side of screen

elif y < 0:

#Left side of screen

To start with we can make the particle stop once it reaches the edge of the window. To do this we will add a function in the Particle class called reflect() and add the code to make the speed 0:

def reflect(self):
if self.x > screen_w: #Bottom of Screen
self.speed = 0
elif self.x < 0: #Top of Screen
self.speed = 0
if self.y > screen_h: #Right side of screen
self.speed = 0
elif self.y < 0: #Left side of Screen
self.speed = 0

The problem with this is that it doesn’t accont for the size of the particle. We need to offset the boundaries by self.size:

def reflect(self):
if self.x > screen_w self.size: #Bottom of Screen
self.speed = 0
elif self.x < self.size: #Top of Screen
self.speed = 0
if self.y > screen_h self.size: #Right side of screen
self.speed = 0
elif self.y < self.size: #Left side of Screen
self.speed = 0

Remember to add a call to reflect() after moving the particle and before displaying:

for particle in particles: # draw the particles
particle.move();
particle.reflect();
particle.display();

Lets make things a little more interesting by bouncing the particles of the walls. This is not quite as simple as we might expect as it is unlikely that a particle will lie exactly on the boundary and will instead overshoot the boundary by a small amount:

Here a particle has moved from A -> B, if it was to reflect of the wall it should be at B’. The y-coordinate will be the same. The x-coordinate will be the screen boundary – dx:
x = screen.w – dx
x = screen.w – (self.x – screen.w)
x = 2*screen.w – self.x
The new angle is:
pi – self.angle
We can perform similar calculations with the other boundaries:
def reflect(self):
if self.x > screen_w self.size: #Right side of screen
self.x = 2*(screen_w self.size) self.x
self.angle = math.pi self.angle
elif self.x < self.size: #Top of Screen
self.x = 2*self.size self.x
self.angle = math.pi self.angle
if self.y > screen_h self.size: #Bottom of Screen
self.y = 2*(screen_h self.size) self.y
self.angle = self.angle
elif self.y < self.size: #Left side of Screen
self.y = 2*self.size self.y
self.angle = self.angle
The particles should now reflect of the walls in a realistic way. In the next tutorial we will have a look at collisions and mouse interaction.