Skip to content

Advanced Graphics with Classes

Eric Dennison edited this page Oct 5, 2015 · 11 revisions

For this tutorial, return to your ggame-tutorials repository that you forked earlier. Create a new file called tutorial4.py and paste the following code into it to get started:

from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# Background
black = Color(0, 1)
noline = LineStyle(0, black)
bg_asset = RectangleAsset(SCREEN_WIDTH, SCREEN_HEIGHT, noline, black)
bg = Sprite(bg_asset, (0,0))


myapp = App(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()

This snippet should look familiar, as it is a "cut down" version of the last tutorial that you worked on (tutorial3.py). Notice that we have removed the step function entirely. In this tutorial, we will add the step function back, but in an entirely different way!

Create a New App Class

For the first part of this tutorial, we would like to customize the behavior of the standard App class by creating an entirely new application class called MyApp that inherits its basic behavior from the standard App class.

Paste the following snippet in just before the myapp = ... line:

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)

Then cut the four lines that create the background and paste them in below the super()... line and indent them to match. Now your code should look like this:

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = RectangleAsset(width, height, noline, black)
        bg = Sprite(bg_asset, (0,0))

Yes, you could have pasted this in from the get-go, but I want you to be very clear about where this code is coming from.

Things to notice about the change:

  • class SpaceGame(App): defines a new class, called SpaceGame, that inherits all of the functionality of the standard App class.
  • The next line defines the __init__ method for the class. In this case it exactly matches the arguments of the App class' version of __init__.
  • The super().__init__(... line forces the new SpaceGame class to call the standard App class' __init__ function before beginning its own initialization. Always do this if you want your new class to fully inherit the behavior of the parent class.
  • Finally, since this code initializes the game, it makes sense to place the code for creating a black background in the __init__ method of the game class.

As it stands, your program is broken. To make the new SpaceGame class take effect, we have to instantiate it instead of instantiating the App class. Change the next to last line of the program to read:

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)

Try running the program. You should see a black background that is 640x480 pixels.

Create a New Sprite Class

Just above your SpaceGame class definition, paste this new code:

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png", 
        Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)

Run your program. It should not do anything different from before. Creating a new Sprite class does not actually create any sprites. All it does is create a blueprint for making sprites.

Add a single SpaceShip sprite by adding the following line to the end of the SpaceGame __init__ method:

SpaceShip((100,100))

Now run your code. Cool. Try adding a few more SpaceShip instances:

SpaceShip((150,150))
SpaceShip((200,50))

It looks like you are building a fleet!

The code we added is very simple, but there is one line that needs some explanation:

    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png", 
        Frame(227,0,292-227,125), 4, 'vertical')

The asset variable is created within the class, but outside of any methods. This makes it a class attribute that will be available to all instances of the class. We used this to call the parent Sprite class __init__ method using the syntax: SpaceShip.asset. This approach allows us to create as many instances of the SpaceShip as we want, but without creating multiple assets. There is one object representing the spaceship image, but multiple objects representing the sprites.

This call to create an ImageAsset has more arguments than we used in the previous tutorial. Here's what they are about:

  • The Frame(227,0,292-227,125) argument specifies a rectangular section within the image file. If you look at the image file in Github you will notice that it actually consists of sixteen different spacecraft images, some with rocket thrust and some without. The frame arguments refer to the horizontal and vertical location of the upper left hand corner of the sub-image we want, followed by the width and height of it.
  • The 4 argument means that the asset will actually include four sub-images of the same size as the first, and...
  • The 'vertical' argument means that those four images are arranged vertically in the image file.

All of this additional information means that this asset is ready to animate! It consists of a single spaceship without thrust, and three spaceship images that include a blast of thrust. By selecting which of these frames we want to show at any given time, we can give the appearance of motion within the sprite itself.

Clone this wiki locally