Better Text Drawing with Text Objects

Screenshot of 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().

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