Better Text Drawing with Text Objects

This example shows how to draw text using “text objects.” It can be many
times faster than using arcade.draw_text()
.
If you want to be as efficient as possible, see The Fastest Text Drawing: pyglet Batches.
If you are looking for something simpler, see Slow but Easy Text Drawing.
drawing_text_objects.py
1"""
2Example showing how to draw text to the screen using Text objects.
3This is much faster than using draw_text
4
5If Python and Arcade are installed, this example can be run from the command line with:
6python -m arcade.examples.drawing_text_objects
7"""
8import arcade
9
10WINDOW_WIDTH = 1200
11WINDOW_HEIGHT = 800
12WINDOW_TITLE = "Drawing Text Example"
13DEFAULT_LINE_HEIGHT = 45
14DEFAULT_FONT_SIZE = 20
15
16# Load fonts bundled with Arcade such as the Kenney fonts
17arcade.resources.load_kenney_fonts()
18arcade.resources.load_liberation_fonts()
19
20
21class GameView(arcade.View):
22 """
23 Main application class.
24 """
25
26 def __init__(self,):
27 super().__init__()
28
29 self.background_color = arcade.color.BEIGE
30 self.text_angle = 0
31 self.time_elapsed = 0.0
32
33 # Add the screen title
34 start_x = 0
35 start_y = WINDOW_HEIGHT - DEFAULT_LINE_HEIGHT * 1.5
36 self.title = arcade.Text(
37 "Text Drawing Examples",
38 start_x,
39 start_y,
40 arcade.color.BLACK,
41 DEFAULT_FONT_SIZE * 2,
42 width=WINDOW_WIDTH,
43 align="center",
44 )
45
46 # start_x and start_y make the start point for the text. We draw a dot to make it
47 # easy to see the text in relation to its start x and y.
48 start_x = 10
49 start_y = WINDOW_HEIGHT - DEFAULT_LINE_HEIGHT * 3
50 self.fonts = arcade.Text(
51 "Fonts:",
52 start_x,
53 start_y,
54 arcade.color.FRENCH_WINE,
55 DEFAULT_FONT_SIZE, bold=True,
56 )
57
58 # Move the y value down to create another line of text
59 start_y -= DEFAULT_LINE_HEIGHT
60 self.font_default = arcade.Text(
61 "Default Font (Arial)",
62 start_x,
63 start_y,
64 arcade.color.BLACK,
65 DEFAULT_FONT_SIZE
66 )
67
68 # Show some built-in fonts
69 start_y -= DEFAULT_LINE_HEIGHT
70 self.font_kenney_blocks = arcade.Text(
71 "Kenney Blocks Font",
72 start_x,
73 start_y,
74 arcade.color.BLACK,
75 DEFAULT_FONT_SIZE,
76 font_name="Kenney Blocks",
77 )
78
79 start_y -= DEFAULT_LINE_HEIGHT
80 self.font_kenney_future = arcade.Text(
81 "Kenney Future Font",
82 start_x,
83 start_y,
84 arcade.color.BLACK,
85 DEFAULT_FONT_SIZE,
86 font_name="Kenney Future",
87 )
88
89 start_y -= DEFAULT_LINE_HEIGHT
90 self.font_kenney_high = arcade.Text(
91 "Kenney High Font",
92 start_x,
93 start_y,
94 arcade.color.BLACK,
95 DEFAULT_FONT_SIZE,
96 font_name="Kenney High"
97 )
98
99 start_y -= DEFAULT_LINE_HEIGHT
100 self.font_kenney_high_square = arcade.Text(
101 "Kenney High Square Font",
102 start_x,
103 start_y,
104 arcade.color.BLACK,
105 DEFAULT_FONT_SIZE,
106 font_name="Kenney High Square",
107 )
108
109 start_y -= DEFAULT_LINE_HEIGHT
110 self.font_kenney_mini_square = arcade.Text(
111 "Kenney Mini Square Font",
112 start_x, start_y,
113 arcade.color.BLACK,
114 DEFAULT_FONT_SIZE,
115 font_name="Kenney Mini Square",
116 )
117
118 start_y -= DEFAULT_LINE_HEIGHT
119 self.font_kenney_pixel = arcade.Text(
120 "Kenney Pixel Font",
121 start_x, start_y,
122 arcade.color.BLACK,
123 DEFAULT_FONT_SIZE,
124 font_name="Kenney Pixel",
125 )
126
127 start_y -= DEFAULT_LINE_HEIGHT
128 self.font_kenney_pixel_square = arcade.Text(
129 "Kenney Pixel Square Font",
130 start_x, start_y,
131 arcade.color.BLACK,
132 DEFAULT_FONT_SIZE,
133 font_name="Kenney Pixel Square",
134 )
135
136 start_y -= DEFAULT_LINE_HEIGHT
137 self.font_kenney_rocket = arcade.Text(
138 "Kenney Rocket Font",
139 start_x, start_y,
140 arcade.color.BLACK,
141 DEFAULT_FONT_SIZE,
142 font_name="Kenney Rocket",
143 )
144
145 start_y -= DEFAULT_LINE_HEIGHT
146 self.font_kenney_rocket_square = arcade.Text(
147 "Kenney Rocket Square Font",
148 start_x, start_y,
149 arcade.color.BLACK,
150 DEFAULT_FONT_SIZE,
151 font_name="Kenney Rocket Square",
152 )
153
154 start_y -= DEFAULT_LINE_HEIGHT
155 # When trying to use system fonts, it can be risky to specify
156 # only a single font because someone else's computer might not
157 # have it installed. This is especially true if they run a
158 # different operating system. For example, if you are on Windows
159 # and a friend has a mac or Linux, they might not have the same
160 # fonts. Your game could look different or broken on their computer.
161 # One way around that is to provide multiple options for draw_text
162 # to try. It will use the first one it finds, and use Arial as a
163 # default if it can't find any of them.
164 # In the example below, draw_text is given a tuple of names for very
165 # similar fonts, each of which is common on a different major
166 # operating systems.
167 self.font_times_new_roman = arcade.Text(
168 "Times New Roman (Or closest match on system)",
169 start_x, start_y,
170 arcade.color.BLACK,
171 DEFAULT_FONT_SIZE,
172 font_name=(
173 "Times New Roman", # Comes with Windows
174 "Times", # MacOS may sometimes have this variant
175 # Common on Linux systems + we ship it with Arcade
176 "Liberation Serif"
177 )
178 )
179
180 start_y -= DEFAULT_LINE_HEIGHT
181 self.multi_line_breaks = arcade.Text(
182 "Multi-Line\ntext using\n\\n characters.",
183 start_x, start_y,
184 arcade.color.BLACK,
185 DEFAULT_FONT_SIZE / 2,
186 multiline=True,
187 width=300,
188 )
189
190 start_y -= DEFAULT_LINE_HEIGHT * 1.5
191 self.multiline_wrap = arcade.Text(
192 "Wrapping really long text automatically to a new line. "
193 "The quick brown fox jumped over the lazy dogs.",
194 start_x,
195 start_y,
196 arcade.color.BLACK,
197 DEFAULT_FONT_SIZE / 2,
198 multiline=True,
199 width=300
200 )
201
202 # --- Column 2 ---
203 start_x = 750
204 start_y = WINDOW_HEIGHT - DEFAULT_LINE_HEIGHT * 3
205 self.text_positioning = arcade.Text(
206 "Text Positioning:",
207 start_x,
208 start_y,
209 arcade.color.FRENCH_WINE,
210 DEFAULT_FONT_SIZE,
211 bold=True,
212 )
213
214 # start_x and start_y make the start point for the text.
215 # We draw a dot to make it easy to see the text in relation to
216 # its start x and y.
217 start_y -= DEFAULT_LINE_HEIGHT
218
219 self.default_baseline_left = arcade.Text(
220 "Default of 'baseline' and 'Left'",
221 start_x,
222 start_y,
223 arcade.color.BLACK,
224 DEFAULT_FONT_SIZE,
225 )
226
227 start_y -= DEFAULT_LINE_HEIGHT
228 self.bottom_left = arcade.Text(
229 "'bottom' and 'left'",
230 start_x,
231 start_y,
232 arcade.color.BLACK,
233 DEFAULT_FONT_SIZE,
234 anchor_x="left",
235 anchor_y="bottom",
236 )
237
238 start_y -= DEFAULT_LINE_HEIGHT
239 self.top_left = arcade.Text(
240 "'top' and 'left'",
241 start_x, start_y,
242 arcade.color.BLACK,
243 DEFAULT_FONT_SIZE,
244 anchor_x="left",
245 anchor_y="top",
246 )
247
248 start_y -= DEFAULT_LINE_HEIGHT * 2
249 self.basline_center = arcade.Text(
250 "'baseline' and 'center'",
251 start_x, start_y,
252 arcade.color.BLACK,
253 DEFAULT_FONT_SIZE,
254 anchor_x="center",
255 anchor_y="baseline",
256 )
257
258 start_y -= DEFAULT_LINE_HEIGHT
259 self.baseline_right = arcade.Text(
260 "'baseline' and 'right'",
261 start_x,
262 start_y,
263 arcade.color.BLACK,
264 DEFAULT_FONT_SIZE,
265 anchor_x="right",
266 anchor_y="baseline",
267 )
268
269 start_y -= DEFAULT_LINE_HEIGHT
270 self.center_center = arcade.Text(
271 "'center' and 'center'",
272 start_x,
273 start_y,
274 arcade.color.BLACK,
275 DEFAULT_FONT_SIZE,
276 anchor_x="center",
277 anchor_y="center",
278 )
279
280 start_y -= DEFAULT_LINE_HEIGHT * 4
281 # start_x = 0
282 # start_y = 0
283 self.rotating_text = arcade.Text(
284 "Rotating Text",
285 start_x, start_y,
286 arcade.color.BLACK,
287 DEFAULT_FONT_SIZE,
288 anchor_x="center",
289 anchor_y="center",
290 rotation=self.text_angle
291 )
292
293 def on_update(self, delta_time):
294 self.text_angle += 1
295 self.time_elapsed += delta_time
296
297 def on_draw(self):
298 """
299 Render the screen.
300 """
301 # This command should happen before we start drawing. It will clear
302 # the screen to the background color, and erase what we drew last frame.
303 self.clear()
304
305 # Draw all the text objects
306 # Column 1
307 self.title.draw()
308 self.fonts.draw()
309 self.font_default.draw()
310 self.font_kenney_blocks.draw()
311 self.font_kenney_future.draw()
312 self.font_kenney_high.draw()
313 self.font_kenney_high_square.draw()
314 self.font_kenney_mini_square.draw()
315 self.font_kenney_pixel.draw()
316 self.font_kenney_pixel_square.draw()
317 self.font_kenney_rocket.draw()
318 self.font_kenney_rocket_square.draw()
319 self.font_times_new_roman.draw()
320 self.multi_line_breaks.draw()
321 self.multiline_wrap.draw()
322
323 # Column 2
324 self.text_positioning.draw()
325
326 arcade.draw_point(
327 self.default_baseline_left.x,
328 self.default_baseline_left.y,
329 arcade.color.BARN_RED,
330 5,
331 )
332 self.default_baseline_left.draw()
333
334 arcade.draw_point(
335 self.bottom_left.x,
336 self.bottom_left.y,
337 arcade.color.BARN_RED,
338 5,
339 )
340 self.bottom_left.draw()
341
342 arcade.draw_point(
343 self.top_left.x,
344 self.top_left.y,
345 arcade.color.BARN_RED,
346 5,
347 )
348 self.top_left.draw()
349
350 arcade.draw_point(
351 self.basline_center.x,
352 self.basline_center.y,
353 arcade.color.BARN_RED,
354 5
355 )
356 self.basline_center.draw()
357
358 arcade.draw_point(
359 self.baseline_right.x,
360 self.baseline_right.y,
361 arcade.color.BARN_RED,
362 5,
363 )
364 self.baseline_right.draw()
365
366 arcade.draw_point(
367 self.center_center.x,
368 self.center_center.y,
369 arcade.color.BARN_RED,
370 5,
371 )
372 self.center_center.draw()
373
374 arcade.draw_point(
375 self.rotating_text.x,
376 self.rotating_text.y,
377 arcade.color.BARN_RED,
378 5,
379 )
380 self.rotating_text.rotation = self.text_angle
381 self.rotating_text.draw()
382
383 def on_key_press(self, symbol: int, modifiers: int):
384 """ Handle key press events """
385 if symbol == arcade.key.ESCAPE:
386 self.window.close()
387
388
389def main():
390 """ Main function """
391 # Create a window class. This is what actually shows up on screen
392 window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
393
394 # Create the GameView
395 game = GameView()
396
397 # Show GameView on screen
398 window.show_view(game)
399
400 # Start the arcade game loop
401 arcade.run()
402
403
404if __name__ == "__main__":
405 main()