9. Drawing With Functions

We learned how to draw in How to Draw with Your Computer. In Lab 2: Draw a Picture we applied that to create our own drawing. We learned how to create functions in Creating Functions. In this chapter, we’ll combine all that knowledge to create our own drawing functions.

We’ll do that by expanding on the code you wrote for Lab 2: Draw a Picture.

To show you how, I’m going to start with a similar program and convert it to using functions.

First the original program:

../../_images/snowman1.png
 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
 8arcade.set_background_color(arcade.color.DARK_BLUE)
 9arcade.start_render()
10
11# Draw the ground
12arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
13
14# Draw a snow person
15
16# Snow
17arcade.draw_circle_filled(300, 200, 60, arcade.color.WHITE)
18arcade.draw_circle_filled(300, 280, 50, arcade.color.WHITE)
19arcade.draw_circle_filled(300, 340, 40, arcade.color.WHITE)
20
21# Eyes
22arcade.draw_circle_filled(285, 350, 5, arcade.color.BLACK)
23arcade.draw_circle_filled(315, 350, 5, arcade.color.BLACK)
24
25#  Finish and run
26arcade.finish_render()
27arcade.run()

Ok, it isn’t very fancy, but that will make this process easier to follow.

9.1. Make The main Function

After copying the code into Lab 3, we’ll create a main() function. Put everything in it, and call the main function.

Are those too many lines to indent? You can indent groups of lines by selecting them, and then hitting “tab”. If you want to un-indent a group of lines, hit shift-tab.

 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def main():
 8    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
 9    arcade.set_background_color(arcade.color.DARK_BLUE)
10    arcade.start_render()
11
12    # Draw the ground
13    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
14
15    # Draw a snow person
16
17    # Snow
18    arcade.draw_circle_filled(300, 200, 60, arcade.color.WHITE)
19    arcade.draw_circle_filled(300, 280, 50, arcade.color.WHITE)
20    arcade.draw_circle_filled(300, 340, 40, arcade.color.WHITE)
21
22    # Eyes
23    arcade.draw_circle_filled(285, 350, 5, arcade.color.BLACK)
24    arcade.draw_circle_filled(315, 350, 5, arcade.color.BLACK)
25
26    # Finish and run
27    arcade.finish_render()
28    arcade.run()
29
30
31# Call the main function to get the program started.
32main()

After this, run your program and make sure it still works before proceeding. If it doesn’t work, stop and get help. Continuing will only make the problem harder.

9.2. Make The Drawing Functions

Next, pick an item to move to a function. Start with an easy one if you have it.

9.2.1. Grass Function

I chose grass to start withbecause it was only one line of code, and I wasn’t going to ever try to position it with an x, y coordinate.

 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def main():
13    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
14    arcade.set_background_color(arcade.color.DARK_BLUE)
15    arcade.start_render()
16
17    draw_grass()
18
19    # Draw a snow person
20
21    # Snow
22    arcade.draw_circle_filled(300, 200, 60, arcade.color.WHITE)
23    arcade.draw_circle_filled(300, 280, 50, arcade.color.WHITE)
24    arcade.draw_circle_filled(300, 340, 40, arcade.color.WHITE)
25
26    # Eyes
27    arcade.draw_circle_filled(285, 350, 5, arcade.color.BLACK)
28    arcade.draw_circle_filled(315, 350, 5, arcade.color.BLACK)
29
30    # Finish and run
31    arcade.finish_render()
32    arcade.run()
33
34
35# Call the main function to get the program started.
36main()

Test, and make sure it is working.

9.2.2. Snow Person Function

Now let’s take the more complex snow person and put it in a function.

 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def draw_snow_person():
13    """ Draw a snow person """
14
15    # Snow
16    arcade.draw_circle_filled(300, 200, 60, arcade.color.WHITE)
17    arcade.draw_circle_filled(300, 280, 50, arcade.color.WHITE)
18    arcade.draw_circle_filled(300, 340, 40, arcade.color.WHITE)
19
20    # Eyes
21    arcade.draw_circle_filled(285, 350, 5, arcade.color.BLACK)
22    arcade.draw_circle_filled(315, 350, 5, arcade.color.BLACK)
23
24
25def main():
26    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
27    arcade.set_background_color(arcade.color.DARK_BLUE)
28    arcade.start_render()
29
30    draw_grass()
31    draw_snow_person()
32
33    # Finish and run
34    arcade.finish_render()
35    arcade.run()
36
37
38# Call the main function to get the program started.
39main()

But this draws the snowman only at one spot. I want to draw lots of snowmen, anywhere I put them!

To do this, let’s add an x and y:

../../_images/snowman2.png
 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def draw_snow_person(x, y):
13    """ Draw a snow person """
14
15    # Draw a point at x, y for reference
16    arcade.draw_point(x, y, arcade.color.RED, 5)
17
18    # Snow
19    arcade.draw_circle_filled(300 + x, 200 + y, 60, arcade.color.WHITE)
20    arcade.draw_circle_filled(300 + x, 280 + y, 50, arcade.color.WHITE)
21    arcade.draw_circle_filled(300 + x, 340 + y, 40, arcade.color.WHITE)
22
23    # Eyes
24    arcade.draw_circle_filled(285 + x, 350 + y, 5, arcade.color.BLACK)
25    arcade.draw_circle_filled(315 + x, 350 + y, 5, arcade.color.BLACK)
26
27
28def main():
29    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
30    arcade.set_background_color(arcade.color.DARK_BLUE)
31    arcade.start_render()
32
33    draw_grass()
34    draw_snow_person(50, 50)
35
36    # Finish and run
37    arcade.finish_render()
38    arcade.run()
39
40
41# Call the main function to get the program started.
42main()

But that’s not perfect. If you’ll note, I added a dot at the x and y. The snowman draws way off from the dot, because originally I didn’t try to draw it at 0, 0. I need to recenter the snowman on the dot.

We need to re-center the shape onto the spot we are drawing. Typically you’ll need to subtract from all the x and y values the same amount.

../../_images/snowman3.png
 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def draw_snow_person(x, y):
13    """ Draw a snow person """
14
15    # Draw a point at x, y for reference
16    arcade.draw_point(x, y, arcade.color.RED, 5)
17
18    # Snow
19    arcade.draw_circle_filled(x, 60 + y, 60, arcade.color.WHITE)
20    arcade.draw_circle_filled(x, 140 + y, 50, arcade.color.WHITE)
21    arcade.draw_circle_filled(x, 200 + y, 40, arcade.color.WHITE)
22
23    # Eyes
24    arcade.draw_circle_filled(x - 15, 210 + y, 5, arcade.color.BLACK)
25    arcade.draw_circle_filled(x + 15, 210 + y, 5, arcade.color.BLACK)
26
27
28def main():
29    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
30    arcade.set_background_color(arcade.color.DARK_BLUE)
31    arcade.start_render()
32
33    draw_grass()
34    draw_snow_person(150, 140)
35    draw_snow_person(450, 180)
36
37    # Finish and run
38    arcade.finish_render()
39    arcade.run()
40
41
42# Call the main function to get the program started.
43main()

9.3. How To Animate A Drawing Function

We can animate our drawing if we want. Here are the steps.

9.3.1. Create An on_draw Method

Right now our program only draws our image once. We need to move all the drawing code in our main to an on_draw function. Then we’ll tell the computer to draw that over and over.

Continuing from our last example, our program will look like:

 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def draw_snow_person(x, y):
13    """ Draw a snow person """
14
15    # Draw a point at x, y for reference
16    arcade.draw_point(x, y, arcade.color.RED, 5)
17
18    # Snow
19    arcade.draw_circle_filled(x, 60 + y, 60, arcade.color.WHITE)
20    arcade.draw_circle_filled(x, 140 + y, 50, arcade.color.WHITE)
21    arcade.draw_circle_filled(x, 200 + y, 40, arcade.color.WHITE)
22
23    # Eyes
24    arcade.draw_circle_filled(x - 15, 210 + y, 5, arcade.color.BLACK)
25    arcade.draw_circle_filled(x + 15, 210 + y, 5, arcade.color.BLACK)
26
27
28def on_draw(delta_time):
29    """ Draw everything """
30    arcade.start_render()
31
32    draw_grass()
33    draw_snow_person(150, 140)
34    draw_snow_person(450, 180)
35
36
37def main():
38    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
39    arcade.set_background_color(arcade.color.DARK_BLUE)
40
41    # Call on_draw every 60th of a second.
42    arcade.schedule(on_draw, 1/60)
43    arcade.run()
44
45
46# Call the main function to get the program started.
47main()

Do this with your own program. Nothing will move, but it should still run.

9.3.2. Add Variable To Control Where We Draw Our Item

Next, we are going to create a variable inside of the on_draw function. This variable will hold our x value. Each time we call on_draw, we’ll change x so that it moves to the right.

 1import arcade
 2
 3SCREEN_WIDTH = 800
 4SCREEN_HEIGHT = 600
 5
 6
 7def draw_grass():
 8    """ Draw the ground """
 9    arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, SCREEN_HEIGHT / 3, 0, arcade.color.AIR_SUPERIORITY_BLUE)
10
11
12def draw_snow_person(x, y):
13    """ Draw a snow person """
14
15    # Draw a point at x, y for reference
16    arcade.draw_point(x, y, arcade.color.RED, 5)
17
18    # Snow
19    arcade.draw_circle_filled(x, 60 + y, 60, arcade.color.WHITE)
20    arcade.draw_circle_filled(x, 140 + y, 50, arcade.color.WHITE)
21    arcade.draw_circle_filled(x, 200 + y, 40, arcade.color.WHITE)
22
23    # Eyes
24    arcade.draw_circle_filled(x - 15, 210 + y, 5, arcade.color.BLACK)
25    arcade.draw_circle_filled(x + 15, 210 + y, 5, arcade.color.BLACK)
26
27
28def on_draw(delta_time):
29    """ Draw everything """
30    arcade.start_render()
31
32    draw_grass()
33    draw_snow_person(on_draw.snow_person1_x, 140)
34    draw_snow_person(450, 180)
35
36    # Add one to the x value, making the snow person move right
37    # Negative numbers move left. Larger numbers move faster.
38    on_draw.snow_person1_x += 1
39
40
41# Create a value that our on_draw.snow_person1_x will start at.
42on_draw.snow_person1_x = 150
43
44
45def main():
46    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing with Functions")
47    arcade.set_background_color(arcade.color.DARK_BLUE)
48
49    # Call on_draw every 60th of a second.
50    arcade.schedule(on_draw, 1/60)
51    arcade.run()
52
53
54# Call the main function to get the program started.
55main()

For more information, see the Bouncing Rectangle Example.