BOUNCING BALL 3


We built a bouncing ball (dot) in the previous couple projects -- now let’s move on to building something a bit more dynamic.  Instead of bouncing a single point, we'll bounce a sprite (a digital design), and we'll animate the sprite (have it change) as we move it.

To make things a little simpler for this project, we'll assume the sprite is a fixed size: 3 pixels by 3 pixels (3x3), tough with minor changes to the code, you can change the size to anything that suits your fancy.  To animate the sprite, we'll keep a list of sprites that make up the animation, and we’ll rotate through them on the screen as we move the sprite and update our drawing.

Step 1: Create a sprite

The LED Matrix API has a simple way to create sprites.  You create a text file that has the sprite drawn in text.

Let’s start with just a single 3x3 sprite, we'll animate it later.  To create the sprite, open a new file called ball0.txt, and input the following (or your own design)

3a7

8fa

183

That's a 3x3 sprite that is darkest in the center.  It’s also not symmetrical – it’s darker in the upper right corners, which will give it a cool affect later when we animate it.

Of course, if you don't like the above sprite, then change it.  That's the power of programming it yourself.

A quick test program to see if our sprite looks like we want:

INSERT CODE

from rstem import led
led.erase()
led.sprite(LEDSprite("ball0.txt"))
led.show()

The above is a complete program, which should draw our sprite in the lower left corner of the matrix.  If it doesn't look the way you expect, edit the sprite text file until it does, then move on to the next step.

Step 2: Change point to sprite

Now, given the work you did in Bouncing Ball 2 Project, you're ready to change the ball from a point to your sprite.

First, we’ll initialize the sprite (create it) before jumping into our game loop.  Next, we’ll change the line of code that previously drew a single point to a line of code that will instead draw your sprite.  You'll need to set the position of the sprite when you draw it.

sprite = LEDSprite("ball0.txt")

while True:

...

led.sprite(sprite, (int(x), int(y)))

...

 

If you ran the program as-is, you’d find that the sprite will now go over the right and top edge of the LED matrix – this is because our program is expecting an bouncing object that is only 1 pixel in width, and it doesn’t recognize that the edge is further out.  Remember, the sprite is 3x3, and we are keeping track of the lower left corner of the sprite in our x and y variables.  We need to adjust the collision with the left and top walls.

For example, in the x direction, we need to adjust the collision with the wall by the width of the sprite minus one:

if x >= (led.width() - (sprite.width() - 1)) or x < 0:

and, you'll need to do the same thing for the y direction with the height of the sprite.

 

Step 3: Animate the sprite

Now, to animate the sprite, we'll create four versions of the sprite, each rotated 90 degrees from the first one.  For example, given the ball0.txt we created before, here's ball1.txt:

183

8fa

3a7

You can then create ball2.txt and ball3.txt using the same methodology.

Once we have all four sprites created (ball0, ball1, ball2, and ball3), we are ready to animate.  We make a list of the sprites, and rotate through them.  You could simply create the list using the following code:

sprites = [ LEDSprite("ball0.txt"),

LEDSprite("ball1.txt"),

LEDSprite("ball2.txt"),

LEDSprite("ball3.txt") ]

 

and that will certainly work.  But we're going to use a cool feature of Python called list comprehensions.  If you haven't used them before, they are a simply way to create a list dynamically within the code, in an easy to read format.  

For example, here's how we could create the list above using list comprehensions:

sprites = [LEDSprite("ball%d.txt" % i) for i in range(4)]

The list comprehension above says to create a sprite for i in the range 0 to 3.  For each sprite created, it replaces the %d in the name with the value of i.  The advantage of the above code is it works for any number of balls, just by changing the number in the range() function.

Finally, it’s time to animate the sprite.  That is, every fixed amount of time, we want to change the sprite from one animation to the next one in the list.  For each step in the game loop, we will be moving the ball's position.  However, we don't want to animate the sprite that frequently.  Therefore we'll only change the sprite every few steps:

step += 1

if step % sprite_steps == 0:

n = (n + 1) % len(sprites)

 

The above code uses the modulus operator "%".  Modulus is like division, except that it returns the remainder, not the dividend.  It’s a handy tool when creating loops.       

In the if statement, its used to run the if statement once every strite_steps.  That is, step is incremented each time the above code is run, but "step % sprite_steps" is only equal to 0 once every sprite_steps times.

The second time modulus is used, it causes n to be incremented by one, but once n equals len(sprites), its set back to 0.

 

Step 4: Even More

Try changing the sprite.  It doesn't have to be a square sprite, it can be a rectangle, too.  However, if it’s a rectangle that rotates, the collisions with the walls can get tricky.  We'll do more with collisions in a later project.

prev| next