Lighting Demo

light_demo.py
1"""
2Show how to use lights.
3
4Artwork from https://kenney.nl
5
6If Python and Arcade are installed, this example can be run from the command line with:
7python -m arcade.examples.light_demo
8"""
9import arcade
10from arcade.future.light import Light, LightLayer
11
12WINDOW_WIDTH = 1280
13WINDOW_HEIGHT = 720
14WINDOW_TITLE = "Lighting Demo"
15MOVEMENT_SPEED = 5
16
17VIEWPORT_MARGIN = 200
18HORIZONTAL_BOUNDARY = WINDOW_WIDTH / 2.0 - VIEWPORT_MARGIN
19VERTICAL_BOUNDARY = WINDOW_HEIGHT / 2.0 - VIEWPORT_MARGIN
20# If the player moves further than this boundary away from
21# the camera we use a constraint to move the camera
22CAMERA_BOUNDARY = arcade.LRBT(
23 -HORIZONTAL_BOUNDARY,
24 HORIZONTAL_BOUNDARY,
25 -VERTICAL_BOUNDARY,
26 VERTICAL_BOUNDARY,
27)
28
29# This is the color used for 'ambient light'. If you don't want any
30# ambient light, set it to black.
31AMBIENT_COLOR = (10, 10, 10, 255)
32
33
34class GameView(arcade.View):
35
36 def __init__(self):
37 """ Set up the class. """
38 super().__init__()
39
40 # Sprite lists
41 self.background_sprite_list = None
42 self.player_list = None
43 self.wall_list = None
44 self.player_sprite = None
45
46 # Physics engine
47 self.physics_engine = None
48
49 # Camera
50 self.camera: arcade.camera.Camera2D = None
51
52 # --- Light related ---
53 # List of all the lights
54 self.light_layer = None
55 # Individual light we move with player, and turn on/off
56 self.player_light = None
57
58 def setup(self):
59 """ Create everything """
60
61 # Create camera
62 self.camera = arcade.camera.Camera2D()
63
64 # Create sprite lists
65 self.background_sprite_list = arcade.SpriteList()
66 self.player_list = arcade.SpriteList()
67 self.wall_list = arcade.SpriteList()
68
69 # Create player sprite
70 self.player_sprite = arcade.Sprite(
71 ":resources:images/animated_characters/female_person/femalePerson_idle.png",
72 scale=0.4)
73 self.player_sprite.center_x = 64
74 self.player_sprite.center_y = 270
75 self.player_list.append(self.player_sprite)
76
77 # --- Light related ---
78 # Lights must shine on something. If there is no background sprite or color,
79 # you will just see black. Therefore, we use a loop to create a whole
80 # bunch of brick tiles to go in the background.
81 for x in range(-128, 2000, 128):
82 for y in range(-128, 1000, 128):
83 sprite = arcade.Sprite(":resources:images/tiles/brickTextureWhite.png")
84 sprite.position = x, y
85 self.background_sprite_list.append(sprite)
86
87 # Create a light layer, used to render things to, then post-process and
88 # add lights. This must match the screen size.
89 self.light_layer = LightLayer(WINDOW_WIDTH, WINDOW_HEIGHT)
90 # We can also set the background color that will be lit by lights,
91 # but in this instance we just want a black background
92 self.light_layer.set_background_color(arcade.color.BLACK)
93
94 # Here we create a bunch of lights.
95
96 # Create a small white light
97 x = 100
98 y = 200
99 radius = 100
100 mode = 'soft'
101 color = arcade.csscolor.WHITE
102 light = Light(x, y, radius, color, mode)
103 self.light_layer.add(light)
104
105 # Create an overlapping, large white light
106 x = 300
107 y = 150
108 radius = 200
109 color = arcade.csscolor.WHITE
110 mode = 'soft'
111 light = Light(x, y, radius, color, mode)
112 self.light_layer.add(light)
113
114 # Create three, non-overlapping RGB lights
115 x = 50
116 y = 450
117 radius = 100
118 mode = 'soft'
119 color = arcade.csscolor.RED
120 light = Light(x, y, radius, color, mode)
121 self.light_layer.add(light)
122
123 x = 250
124 y = 450
125 radius = 100
126 mode = 'soft'
127 color = arcade.csscolor.GREEN
128 light = Light(x, y, radius, color, mode)
129 self.light_layer.add(light)
130
131 x = 450
132 y = 450
133 radius = 100
134 mode = 'soft'
135 color = arcade.csscolor.BLUE
136 light = Light(x, y, radius, color, mode)
137 self.light_layer.add(light)
138
139 # Create three, overlapping RGB lights
140 x = 650
141 y = 450
142 radius = 100
143 mode = 'soft'
144 color = arcade.csscolor.RED
145 light = Light(x, y, radius, color, mode)
146 self.light_layer.add(light)
147
148 x = 750
149 y = 450
150 radius = 100
151 mode = 'soft'
152 color = arcade.csscolor.GREEN
153 light = Light(x, y, radius, color, mode)
154 self.light_layer.add(light)
155
156 x = 850
157 y = 450
158 radius = 100
159 mode = 'soft'
160 color = arcade.csscolor.BLUE
161 light = Light(x, y, radius, color, mode)
162 self.light_layer.add(light)
163
164 # Create three, overlapping RGB lights
165 # But 'hard' lights that don't fade out.
166 x = 650
167 y = 150
168 radius = 100
169 mode = 'hard'
170 color = arcade.csscolor.RED
171 light = Light(x, y, radius, color, mode)
172 self.light_layer.add(light)
173
174 x = 750
175 y = 150
176 radius = 100
177 mode = 'hard'
178 color = arcade.csscolor.GREEN
179 light = Light(x, y, radius, color, mode)
180 self.light_layer.add(light)
181
182 x = 850
183 y = 150
184 radius = 100
185 mode = 'hard'
186 color = arcade.csscolor.BLUE
187 light = Light(x, y, radius, color, mode)
188 self.light_layer.add(light)
189
190 # Create a light to follow the player around.
191 # We'll position it later, when the player moves.
192 # We'll only add it to the light layer when the player turns the light
193 # on. We start with the light off.
194 radius = 150
195 mode = 'soft'
196 color = arcade.csscolor.WHITE
197 self.player_light = Light(0, 0, radius, color, mode)
198
199 # Create the physics engine
200 self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
201
202 def on_draw(self):
203 """ Draw everything. """
204 self.clear()
205
206 # --- Light related ---
207 # Everything that should be affected by lights gets rendered inside this
208 # 'with' statement. Nothing is rendered to the screen yet, just the light
209 # layer.
210 with self.light_layer:
211 self.background_sprite_list.draw()
212 self.player_list.draw()
213
214 # Draw the light layer to the screen.
215 # This fills the entire screen with the lit version
216 # of what we drew into the light layer above.
217 self.light_layer.draw(ambient_color=AMBIENT_COLOR)
218
219 # Now draw anything that should NOT be affected by lighting.
220 left, bottom = self.camera.bottom_left
221 arcade.draw_text("Press SPACE to turn character light on/off.",
222 10 + int(left), 10 + int(bottom),
223 arcade.color.WHITE, 20)
224
225 def on_resize(self, width, height):
226 """ User resizes the screen. """
227 super().on_resize(width, height)
228 self.camera.match_window()
229
230 # --- Light related ---
231 # We need to resize the light layer to
232 self.light_layer.resize(width, height)
233
234 # Scroll the screen so the user is visible
235 self.scroll_screen()
236
237 def on_key_press(self, key, _):
238 """Called whenever a key is pressed. """
239
240 if key == arcade.key.UP:
241 self.player_sprite.change_y = MOVEMENT_SPEED
242 elif key == arcade.key.DOWN:
243 self.player_sprite.change_y = -MOVEMENT_SPEED
244 elif key == arcade.key.LEFT:
245 self.player_sprite.change_x = -MOVEMENT_SPEED
246 elif key == arcade.key.RIGHT:
247 self.player_sprite.change_x = MOVEMENT_SPEED
248 elif key == arcade.key.SPACE:
249 # --- Light related ---
250 # We can add/remove lights from the light layer. If they aren't
251 # in the light layer, the light is off.
252 if self.player_light in self.light_layer:
253 self.light_layer.remove(self.player_light)
254 else:
255 self.light_layer.add(self.player_light)
256
257 def on_key_release(self, key, _):
258 """Called when the user releases a key. """
259
260 if key == arcade.key.UP or key == arcade.key.DOWN:
261 self.player_sprite.change_y = 0
262 elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
263 self.player_sprite.change_x = 0
264
265 def scroll_screen(self):
266 """ Manage Scrolling """
267
268 # --- Manage Scrolling ---
269 self.camera.position = arcade.camera.grips.constrain_boundary_xy(
270 self.camera.view_data, CAMERA_BOUNDARY, self.player_sprite.position
271 )
272
273 self.camera.use()
274
275 def on_update(self, delta_time):
276 """ Movement and game logic """
277
278 # Call update on all sprites (The sprites don't do much in this
279 # example though.)
280 self.physics_engine.update()
281
282 # --- Light related ---
283 # We can easily move the light by setting the position,
284 # or by center_x, center_y.
285 self.player_light.position = self.player_sprite.position
286
287 # Scroll the screen so we can see the player
288 self.scroll_screen()
289
290
291def main():
292 """ Main function """
293 # Create a window class. This is what actually shows up on screen
294 window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
295
296 # Create and setup the GameView
297 game = GameView()
298 game.setup()
299
300 # Show GameView on screen
301 window.show_view(game)
302
303 # Start the arcade game loop
304 arcade.run()
305
306
307if __name__ == "__main__":
308 main()