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
 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()