.. _simple-animation: Animating your graphics ####################### After creating your best art work for the refrigerator art project, it is time for something more fun. Let's try to make something move on the screen. This is a great way to experiment with loops and decisions in Python! Creating the window ******************* As usual, we need a window to draw in: .. literalinclude:: code/pool1.py The new line, ``win.setBackground('yellow')`` makes the entire window background color yellow, in this case. Remember that objects you draw will show this background unless you fill them with a color. Here is what you should see: .. image:: pool1.png :align: center Adding a ball ************* Now, we need a ball, which is just a circle we will place in the middle of the screen. To make finding this spot easier, let's use a few constants in this modification .. literalinclude:: code/pool2.py In this example, we have put a call to the ``Point`` function inside the call to the ``Circle`` function. We could have used a variable to do this, but this saves a bit of typing and works just fine. It is important that you understand how this works. The ``Circle`` function expects a ``Point`` variable as its first parameter. In previous examples, we called the ``Point`` function and saved the result in a variable. By placing the call to ``Point`` in the parameter list for ``Circle, the value returned by ``Point`` is simply passed directly into the ``Circle`` function. That last value, 25, is the radius of the circle we want to draw. Phew! Here is what we get now: .. image:: pool2.png :align: center Moving the ball *************** Now for the fun part, making the ball move is incredibly easy, thanks to the smart design of the ``graphics`` code. We have a ``method`` available for each object we create (like the ball) that makes it move! Here is the code: .. literalinclude:: code/pool3.py Look closely at this code. We are using a new library here, called ``time``. This library has one important function in it, one that will effectively puts your program to "sleep" for a short period of time. In this example, we are asking the program to sleep for one half of a second every time we move the ball. .. note:: I have placed a call to the ``win.getMouse()`` function to stop the program just before the loop. You will need to click once to start the motion, and again to end the program. Running this will make the ball slide across the screen. Cool! Look closely at what we just did. We set up a counted loop using the ``for`` loop statement. We set up a simple variable named ``i`` whose sole purpose is to keep track of how many times we have run through the loop. Inside the body of the loop, we simply called the ``move`` ``method`` that the ball knows about and asked it to move a small distance in the ``X,Y`` direction. Since we set the ``Y`` amount to zero, the ball slides to the right. When the loops ends, the movement stops. This use of the ``for`` loop is fine when you know that you want to stop looping at some point. There are times when we do not know when we want to stop. We will get to that soon! Moving at an angle ****************** Let's add in a few more constants to make this a bit easier: .. literalinclude:: code/pool4.py This time we have set up constants for the amount in the X and Y direction we want the ball to move each time we pass through the loop (``DX`` and ``DY``). The delay at the end is controlled by the ``SPEED`` constant. Now, the ball moves at an angle toward the bottom right of the screen. Playing with those ``DX`` and ``DY`` values will make it move at other angles. Try it and see! Boing! ****** Suppose this ball is a model of a real pool ball, and the window we are drawing in is the pool table. As the ball moves to the right, eventually it will hits the edge of the window. What should happen? Well to figure this out, we need to figure out two things Have we hit the wall yet? ========================= This one is harder than it should be, but makes sense after a bit of thinking. Remember that we are working with those funny ``object`` critters in all this. The ``Circle`` object has a ``method`` that will tell you where the center currently is. If we call that method, ``getCenter()``, we will get back another ``object`` which is one of those ``Point`` objects. The ``Point`` object can tell you where it is using the ``getX()`` and ``getY()`` methods. Sounds complicated, but it is not so bad. Here is the code we need: .. code-block:: python center = ball.getCenter() current_x = center.getX() current_y = center.getY() See, it was not so bad! It does help to study the reference material for the graphics module. Here is the PDF file: * `graphics.pdf `_ The ``Circle`` object we have created has another object at the center, a ``Point``. The ``Circle`` object knows how to tell you where the center is. If we call the ``getCenter()`` method, it will return a ``Point`` that is at the current center of the ``Circle``. We can call the ``getX()`` method to fetch the actual coordinate value. What do we do to "bounce"? ========================== This one is simple, we move away from the wall. If moving toward the wall was done by setting ``DX`` to a positive value, all we need to do is make it negative. Try this: .. code-block:: python if current_x >= WIDTH - RADIUS: DX = -DX .. warning:: Remember our discussion on global and local variables. If we ask Python to use this line inside a function (like main in this case), Python will create a new ``local`` variable with the same name as the ``global`` variable we really want it to use. The cure for this is to add this line inside main (after the "def" line): .. code-block:: python global DX, DY This tells Python that the names ``DX`` and ``DY`` we want to use in this function are the ``global`` ones. .. vim:filetype=rst spell: