More Graphics: Assets and Looping - Runpython-IntroProgramming/Course-Syllabus GitHub Wiki
This tutorial will show you how to add the following features to your ggame based applications:
- Image-based sprite assets.
- Sound assets.
- Respond to keyboard input.
- Respond to mouse button.
- Movement.
Fork the Tutorial Repository
Visit the ggame-tutorials repository and fork a copy to your own Github account. This repository consists only of assets that we will use for the final ggame tutorials.
After forking, add a new Python source file (press the +
link for your new
repository) and name it tutorial3.py
. You can insert a comment at the top of the file
with your name and the name of the file then commit it. Copy the URL for the file and load it
up in Runpython.
Now start by pasting in some "boilerplate" code for our tutorial. This should look familiar:
from ggame import App, RectangleAsset, ImageAsset, SoundAsset
from ggame import LineStyle, Color, Sprite, Sound
myapp = App()
myapp.run()
If you test your program now it should open a blank window in your editor tab, but that's about all.
Retrieve Graphics Area Size
In the past tutorial and graphics assignments we have used all of the available space
in the browser for our graphics. For this one, we would like to know how big that space
is and use that size to create a colored background for the app. Insert the following lines after
the myapp = App()
line, and before the myapp.run()
line:
# define colors and line style
green = Color(0x00ff00, 1)
black = Color(0, 1)
noline = LineStyle(0, black)
# a rectangle asset and sprite to use as background
bg_asset = RectangleAsset(myapp.width, myapp.height, noline, green)
bg = Sprite(bg_asset, (0,0))
Once we have created the myapp
object, we can use two of its properties,
width and height, in our program. Commit, then run your app to see the difference.
You should see that the entire graphics window is green.
Image Assets
Next, add the following lines to your program, after the other asset and sprite lines,
but before the myapp.run()
line:
# A ball! This is already in the ggame-tutorials repository
ball_asset = ImageAsset("images/orb-150545_640.png")
ball = Sprite(ball_asset, (0, 0))
# Original image is too big. Scale it to 1/10 its original size
ball.scale = 0.1
# custom attributes
ball.direction = 1
ball.go = True
Step by step, here is what we have added:
- The
ImageAsset
function creates an image asset from an image file already in theggame-tutorials
repository. If you go back to the Github pages for your forked repository you can click on theimages
link in the file list to see all the images included in the repository. - The
Sprite
function makes a sprite from the image asset, just the way it did in the earlier tutorials and assignments. - Since the image asset we are using is a very large image, the
ball.scale = 0.1
line will shrink the displayed image on your screen to 1/10 its original size. - The next two lines actually create two attributes of the ball sprite that
don't already exist in Sprite objects. The first is a number (
direction
) that will represent the direction the sprite is moving. The second is a boolean (True or False) attribute (go
) that will indicate whether the sprite is moving.
Make Your Own Function
So far you have been using functions in Python. A function is a name that
refers to a collection of Python code that you can run at any time. For example, the
print
function executes code that displays text on the computer console.
To use a function, you type the name of the function, followed by ()
. If the
function accepts additional information (like the print
function does), then
you insert that information inside the ()
. If you are expected to insert
more than one piece of information, then you separate items with commas.
Now it is time to create your own functions! Insert the following code in your
tutorial (immediately after the code you already added, but before the myapp.run()
line):
# reverse - change the ball direction
def reverse(b):
b.direction *= -1
This code uses the special keyword def
to define a new function. The
name of the function is reverse
and it accepts one parameter, b
. The
name b
is used only inside the definition of the function. When you call
the function reverse
, you typically insert a different name in the parentheses.
In our case, we intend to call the reverse
function and give it the name of
our sprite (ball
). The reverse
does one small thing: it takes whatever
the value of the ball's direction
is and multiplies it by -1.
If you create a function that should return a value then use Python's return
keyword (e.g. return 99
).
Note: you have created simple functions already using the lambda
statement.
The def
keyword allows you to create functions with multiple lines. All of
the code inside the function must be indented.
Execute Code Repeatedly
The execution of a graphical computer game implies an infinite loop. The graphics display is changed and redrawn many times per second and each time this happens computer code needs to run in order to figure out how the screen should be redrawn. In a ggame program, the code that does this is known as the step function.
Next, add the following function to your tutorial code (after the reverse
function,
but just before the myapp.run()
line):
# Set up function for handling screen refresh
def step():
if ball.go:
ball.x += ball.direction
if ball.x + ball.width > myapp.width or ball.x < 0:
ball.x -= ball.direction
reverse(ball)
This function is intended to be run once every time the screen updates. It
checks to see if the ball should be moving (ball.go
is True), increments
the x position of the ball with the value of ball.dir
, then checks
to see if the ball has moved to the edge of the game screen. Do you see how
this function doesn't need to know exactly how many pixels wide the screen
is?
Finally, if the function decides that the ball needs to change direction,
it calls the reverse
function that we created earlier.
Before we can try the program, we have to tell myapp
that our step
function exists. Change the last line of your program from myapp.run()
to myapp.run(step)
. Remember: step
is the name of the function
you just created; the application will call your step
function over and
over again.
Now run it!
Handle User Input
Computer games are much more fun if you get to control them in some way,
so let's add mouse and keyboard controls. Insert the following function
definitions after your step
function, but before the myapp.run(step)
line:
# Handle the space key
def spaceKey(event):
ball.go = not ball.go
# Handle the "reverse" key
def reverseKey(event):
reverse(ball)
# Handle the mouse click
def mouseClick(event):
ball.x = event.x
ball.y = event.y
These functions are supposed to be executed when the "space" and
"reverse" keys are pressed, and when the mouse button is pressed.
However, we need to tell the App about them in order for them to
work. Insert the following code before the myapp.run(step)
line:
# Set up event handlers for the app
myapp.listenKeyEvent('keydown', 'space', spaceKey)
myapp.listenKeyEvent('keydown', 'r', reverseKey)
myapp.listenMouseEvent('click', mouseClick)
The listenKeyEvent
method of the application will tell it
to "listen" for buttons to be pressed ('keydown'
), and which
specific key to listen for ('space'
and 'r'
) on the
keyboard. If the keys are pressed then the applicaiton will call
the functions spaceKey
and reverseKey
, respectively.
Note: the functions you create to handle keypresses must accept an
event
argument.
The listenMouseEvent
method listens for the user to do
something with the mouse. In this case, we're only waiting for
the user to 'click'
the mouse button. In response, the
application will call the mouseClick
function that
we created.
Note: you can call your mouse and keyboard event handler functions whatever you want.
Run the program and experiment with space, r and mouse button. Do you understand how the program works?
Sounds
For the last piece, we will add a couple of sounds to the game. Insert the following lines near where your other assets are created:
# Sounds
pew1_asset = SoundAsset("sounds/pew1.mp3")
pew1 = Sound(pew1_asset)
pop_asset = SoundAsset("sounds/reappear.mp3")
pop = Sound(pop_asset)
Then add the line, pew1.play()
, inside the mouseClick
function.
Add the line pop.play()
, inside the reverse
function.
Your final program should look something like this:
"""
tutorial3.py
by E. Dennison
"""
from ggame import App, RectangleAsset, ImageAsset, SoundAsset
from ggame import LineStyle, Color, Sprite, Sound
myapp = App()
# define colors and line style
green = Color(0x00ff00, 1)
black = Color(0, 1)
noline = LineStyle(0, black)
# a rectangle asset and sprite to use as background
bg_asset = RectangleAsset(myapp.width, myapp.height, noline, green)
bg = Sprite(bg_asset, (0,0))
# A ball! This is already in the ggame-tutorials repository
ball_asset = ImageAsset("images/orb-150545_640.png")
ball = Sprite(ball_asset, (0, 0))
# Original image is too big. Scale it to 1/10 its original size
ball.scale = 0.1
# custom attributes
ball.direction = 1
ball.go = True
# Sounds
pew1_asset = SoundAsset("sounds/pew1.mp3")
pew1 = Sound(pew1_asset)
pop_asset = SoundAsset("sounds/reappear.mp3")
pop = Sound(pop_asset)
# reverse - change the ball direction
def reverse(b):
pop.play()
b.direction *= -1
# Set up function for handling screen refresh
def step():
if ball.go:
ball.x += ball.direction
if ball.x + ball.width > myapp.width or ball.x < 0:
ball.x -= ball.direction
reverse(ball)
# Handle the space key
def spaceKey(event):
ball.go = not ball.go
# Handle the "reverse" key
def reverseKey(event):
reverse(ball)
# Handle the mouse click
def mouseClick(event):
pew1.play()
ball.x = event.x
ball.y = event.y
# Set up event handlers for the app
myapp.listenKeyEvent('keydown', 'space', spaceKey)
myapp.listenKeyEvent('keydown', 'r', reverseKey)
myapp.listenMouseEvent('click', mouseClick)
myapp.run(step)
Play With It
Feel free to play with the app and substitute other assets. Enjoy!