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