Lights#

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