Bouncing Ball with Gravity

Screen shot of bouncing ball
bouncing_ball.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Bounce a ball on the screen, using gravity.

If Python and Arcade are installed, this example can be run from the command line with:
python -m arcade.examples.bouncing_ball
"""

import arcade

# --- Set up the constants

# Size of the screen
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Bouncing Ball Example"

# Size of the circle.
CIRCLE_RADIUS = 20

# How strong the gravity is.
GRAVITY_CONSTANT = 0.3

# Percent of velocity maintained on a bounce.
BOUNCINESS = 0.9


def draw(_delta_time):
    """
    Use this function to draw everything to the screen.
    """

    # Start the render. This must happen before any drawing
    # commands. We do NOT need an stop render command.
    arcade.start_render()

    # Draw our rectangle
    arcade.draw_circle_filled(draw.x, draw.y, CIRCLE_RADIUS,
                              arcade.color.BLACK)

    # Modify rectangles position based on the delta
    # vector. (Delta means change. You can also think
    # of this as our speed and direction.)
    draw.x += draw.delta_x
    draw.y += draw.delta_y

    draw.delta_y -= GRAVITY_CONSTANT

    # Figure out if we hit the left or right edge and need to reverse.
    if draw.x < CIRCLE_RADIUS and draw.delta_x < 0:
        draw.delta_x *= -BOUNCINESS
    elif draw.x > SCREEN_WIDTH - CIRCLE_RADIUS and draw.delta_x > 0:
        draw.delta_x *= -BOUNCINESS

    # See if we hit the bottom
    if draw.y < CIRCLE_RADIUS and draw.delta_y < 0:
        # If we bounce with a decent velocity, do a normal bounce.
        # Otherwise we won't have enough time resolution to accurate represent
        # the bounce and it will bounce forever. So we'll divide the bounciness
        # by half to let it settle out.
        if draw.delta_y * -1 > GRAVITY_CONSTANT * 15:
            draw.delta_y *= -BOUNCINESS
        else:
            draw.delta_y *= -BOUNCINESS / 2


# Below are function-specific variables. Before we use them
# in our function, we need to give them initial values. Then
# the values will persist between function calls.
#
# In other languages, we'd declare the variables as 'static' inside the
# function to get that same functionality.
#
# Later on, we'll use 'classes' to track position and velocity for multiple
# objects.
draw.x = CIRCLE_RADIUS                  # type: ignore # dynamic attribute on function obj  # Initial x position
draw.y = SCREEN_HEIGHT - CIRCLE_RADIUS  # type: ignore # dynamic attribute on function obj  # Initial x position
draw.delta_x = 2                        # type: ignore # dynamic attribute on function obj  # Initial x position
draw.delta_y = 0                        # type: ignore # dynamic attribute on function obj  # Initial x position


def main():
    # Open up our window
    arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    arcade.set_background_color(arcade.color.WHITE)

    # Tell the computer to call the draw command at the specified interval.
    arcade.schedule(draw, 1 / 80)

    # Run the program
    arcade.run()

    # When done running the program, close the window.
    arcade.close_window()


if __name__ == "__main__":
    main()