Shape List - Skylines

Screenshot of using shape list to create a moving skyline
shape_list_demo_skylines.py
  1"""
  2City Scape Generator
  3
  4If Python and Arcade are installed, this example can be run from the command line with:
  5python -m arcade.examples.shape_list_demo_skylines
  6"""
  7import random
  8import arcade
  9from arcade.shape_list import (
 10    ShapeElementList,
 11    create_rectangle_filled,
 12    create_polygon,
 13    create_rectangles_filled_with_colors,
 14)
 15
 16WINDOW_WIDTH = 1200
 17WINDOW_HEIGHT = 600
 18WINDOW_TITLE = "Skyline Using Buffered Shapes"
 19
 20
 21def make_star_field(star_count):
 22    """Make a bunch of circles for stars"""
 23    shape_list = ShapeElementList()
 24
 25    for _ in range(star_count):
 26        x = random.randrange(WINDOW_WIDTH)
 27        y = random.randrange(WINDOW_HEIGHT)
 28        radius = random.randrange(1, 4)
 29        brightness = random.randrange(127, 256)
 30        color = (brightness, brightness, brightness)
 31        shape = create_rectangle_filled(x, y, radius, radius, color)
 32        shape_list.append(shape)
 33
 34    return shape_list
 35
 36
 37def make_skyline(width, skyline_height, skyline_color,
 38                 gap_chance=0.70, window_chance=0.30, light_on_chance=0.5,
 39                 window_color=(255, 255, 200), window_margin=3, window_gap=2,
 40                 cap_chance=0.20):
 41    """Make a skyline of buildings"""
 42    shape_list = ShapeElementList()
 43
 44    # Add the "base" that we build the buildings on
 45    shape = create_rectangle_filled(
 46        center_x=width / 2,
 47        center_y=skyline_height / 2,
 48        width=width,
 49        height=skyline_height,
 50        color=skyline_color,
 51    )
 52    shape_list.append(shape)
 53
 54    building_center_x = 0
 55
 56    skyline_point_list = []
 57    color_list = []
 58
 59    while building_center_x < width:
 60
 61        # Is there a gap between the buildings?
 62        if random.random() < gap_chance:
 63            gap_width = random.randrange(10, 50)
 64        else:
 65            gap_width = 0
 66
 67        # Figure out location and size of building
 68        building_width = random.randrange(20, 70)
 69        building_height = random.randrange(40, 150)
 70        building_center_x += gap_width + (building_width / 2)
 71        building_center_y = skyline_height + (building_height / 2)
 72
 73        x1 = building_center_x - building_width / 2
 74        x2 = building_center_x + building_width / 2
 75        y1 = skyline_height
 76        y2 = skyline_height + building_height
 77
 78        skyline_point_list.append([x1, y1])
 79        skyline_point_list.append([x1, y2])
 80        skyline_point_list.append([x2, y2])
 81        skyline_point_list.append([x2, y1])
 82
 83        for i in range(4):
 84            color_list.append([skyline_color[0], skyline_color[1], skyline_color[2]])
 85
 86        if random.random() < cap_chance:
 87            x1 = building_center_x - building_width / 2
 88            x2 = building_center_x + building_width / 2
 89            x3 = building_center_x
 90
 91            y1 = y2 = building_center_y + building_height / 2
 92            y3 = y1 + building_width / 2
 93
 94            # Roof
 95            shape = create_polygon([[x1, y1], [x2, y2], [x3, y3]], skyline_color)
 96            shape_list.append(shape)
 97
 98        # See if we should have some windows
 99        if random.random() < window_chance:
100            # Yes windows! How many windows?
101            window_rows = random.randrange(10, 15)
102            window_columns = random.randrange(1, 7)
103
104            # Based on that, how big should they be?
105            window_height = (building_height - window_margin * 2) / window_rows
106            window_width = (
107                (building_width - window_margin * 2 - window_gap * (window_columns - 1))
108                / window_columns
109            )
110
111            # Find the bottom left of the building so we can start adding widows
112            building_base_y = building_center_y - building_height / 2
113            building_left_x = building_center_x - building_width / 2
114
115            # Loop through each window
116            for row in range(window_rows):
117                for column in range(window_columns):
118                    if random.random() > light_on_chance:
119                        continue
120
121                    x1 = (
122                        building_left_x
123                        + column * (window_width + window_gap)
124                        + window_margin
125                    )
126                    x2 = (
127                        building_left_x
128                        + column * (window_width + window_gap)
129                        + window_width
130                        + window_margin
131                    )
132                    y1 = building_base_y + row * window_height
133                    y2 = building_base_y + row * window_height + window_height * .8
134
135                    skyline_point_list.append([x1, y1])
136                    skyline_point_list.append([x1, y2])
137                    skyline_point_list.append([x2, y2])
138                    skyline_point_list.append([x2, y1])
139
140                    for i in range(4):
141                        color_list.append((
142                            window_color[0],
143                            window_color[1],
144                            window_color[2],
145                        ))
146
147        building_center_x += (building_width / 2)
148
149    shape = create_rectangles_filled_with_colors(skyline_point_list, color_list)
150    shape_list.append(shape)
151
152    return shape_list
153
154
155class GameView(arcade.View):
156    """ Main application class. """
157
158    def __init__(self):
159        """ Initializer """
160        # Call the parent class initializer
161        super().__init__()
162        # Enable vertical sync to make scrolling smoother
163        self.window.set_vsync(True)
164
165        self.stars = make_star_field(150)
166        self.skyline1 = make_skyline(WINDOW_WIDTH * 5, 250, (80, 80, 80))
167        self.skyline2 = make_skyline(WINDOW_WIDTH * 5, 150, (50, 50, 50))
168
169        self.background_color = arcade.color.BLACK
170
171    def on_draw(self):
172        """Draw to screen"""
173        self.clear()
174
175        self.stars.draw()
176        self.skyline1.draw()
177        self.skyline2.draw()
178
179    def on_update(self, delta_time):
180        """Per frame update logic"""
181        # Scroll each shape list with a slight offset to give a parallax effect
182        self.skyline1.center_x -= 0.5 * 60 * delta_time
183        self.skyline2.center_x -= 1 * 60 * delta_time
184
185    def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int):
186        """Make it possible scroll the scene around by dragging the mouse"""
187        self.skyline1.center_x += dx
188        self.skyline1.center_y += dy
189
190        self.skyline2.center_x += dx
191        self.skyline2.center_y += dy
192
193
194def main():
195    """ Main function """
196    # Create a window class. This is what actually shows up on screen
197    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
198
199    # Create the GameView
200    game = GameView()
201
202    # Show GameView on screen
203    window.show_view(game)
204
205    # Start the arcade game loop
206    arcade.run()
207
208
209if __name__ == "__main__":
210    main()