Lecture 16 | How to load UI and menus in the game?

Today we are going to load the UI and menu in the game. Before we start, let’s adjust the content of the game code we talked about before.

First we need to change the background image of the game to make it look more like a masturbation game, rather than the random landscape picture we used before. We first change the game background to a normal game background and paste the airplane image.

Here, I thought of a question. Someone previously left a message asking me whether programmers need to have art skills. Let me tell you my opinion here. If you just want to be a programmer, then I can tell you, no need. However, if you don’t just want to be a “code farmer” and want to develop more, then you need to understand all aspects of knowledge, such as planning and art.

Two presentation forms of UI

Closer to home, we need to add a series of content to this game screen to represent the presentation of the UI. There are two forms of UI presentation:

The first is to draw the UI picture in art, then directly paste it, and use the mouse to control a series of click and press operations;

The other is to draw the UI interface yourself, such as drawing a box and writing text inside the box.

There are pros and cons to both approaches.

If you use artistic UI graphics, the advantage is that it can reduce the programmer’s workload. In this way, when the version is iterated, the interface can be modified by changing the art, which is convenient and fast, and you don’t need to do extra work. But the disadvantage of this is that it increases the size of the game installation package. After all, the UI is a picture, and as long as it is a picture, it will have a certain volume, which will increase the size of the installation package.

If the UI interface is drawn by the programmer himself, the advantage is that the size of the main program becomes slightly larger, but the game installation package does not become larger. But the disadvantage of this is also obvious, that is, the workload of programmers will increase a lot. Moreover, when the game needs to be iterated, or the interface needs to be updated, programmers need to redraw or rewrite the UI source code, which greatly increases the workload.

We are developing it ourselves now, so I will talk about how programmers draw UI.

We place the UI interfaceby simulating buttons. First, we need to place a series of characters on the UI interface. The effect we want to achieve is that as long as the mouse is clicked on this character, the content of the character will be changed. In this process, we will use knowledge related to mouse operation, rectangle drawing, fonts and character drawing, which will be discussed in detail below.

Mouse operation

Let’s first take a look at the knowledge of mouse operations. In Pygame, the module used for mouse operations is pygame.mouse. In this module, the function of the click event is get_pressed. If there are many buttons such as return button 1, button 2, and button 3, we can choose a point at random. If button 1 is selected, the code can be written like this:

pygame.mouse.get_pressed()[0]

This statement does not need to be operated in the event statement, it can be written elsewhere, and the mouse operation is always monitored in real time in the loop.

Draw a rectangle

Next, we’re going to draw the rectangle. The purpose of drawing a rectangle is to simulate a button. The code for rectangular drawing is Rect, but we need to draw it on a surface. This surface needs to be newly created. However, in pygame, if you use pygame.surface.surface to initialize a surface, you cannot specify the position, and the x value starts from 0.

So the newly created surface you see on the screen is a long strip layer, so we need to generate a sublayer of the layer, and if you use this sublayer, you will be prompted when blit Locked, so we also need to copy this sublayer. So, our code looks like this.

the_rect = Rect(200, 100, 150, 40)
block_surface = screen.subsurface(the_rect).copy()

First, the first line of code is to create a rectangle with a starting value of 200 on the left side, 100 on the top, a width of 150, and a length of 40. Then, use the screen layer to create a sublayer, and the size of the sublayer is based on the size of the rectangle the_rect. A subsequent copy function copies the sublayer. In subsequent uses, the layer will not be locked.

Draw fonts and characters

After that, we will start writing word processing code. For fonts, we will use the pygame.font module. We first initialize a font. This font is included in pygame when the pygame game library is installed, and we can use it directly. Now we initialize the font and adjust the font size to 25:

fnt = pygame.font.Font('freesansbold.ttf',25)

Among them, freesansbold.ttf is the ttf font file that exists by default when pygame is installed. Then, we set the second parameter to size 25.

We get the fnt object and use this object to call the render function. This is actually rendering, rendering text on the screen and forming a text layer. The function prototype is like this:

Font.render(text, antialias, color, background=None)

The first parameter text is the text content, the second parameter antialias is anti-aliasing, the third content color is the text color, and the last one is the background color, which can be ignored by default.

tsurf = fnt.render(text, True, (255,255,255))

We set the color to white, so (255, 255, 255).

tsurf is a text layer (surface) returned by render. We will later use this layer to determine its rectangular frame.

trect = tsurf.get_rect()

Then we need to place the text in the center of this trect rectangular box, so we need to further determine the position of trect in the center, calculate the coordinate value of the center and assign it.

trect.center = ((block_surface.get_width()/2),(block_surface.get_height()/2))

We divide the width and height of the first copied sublayer by 2 to get the position of the center point.

The last thing we have to do is include the blit part within the wrapped function. Now let’s take a look at the complete wrapper function code.

def text_out(text):
    fnt = pygame.font.Font('freesansbold.ttf',25)
    tsurf = fnt.render(text, True, (255,255,255))
    trect = tsurf.get_rect()
    trect.center = ((block_surface.get_width()/2),(block_surface.get_height()/2))
    block_surface.blit(tsurf, trect)

We see that at the end of the function, we blit the copied layer block_surface.

Then we need to determine the mouse click event in the big loop of the game. The rectangle we defined before, the code is as follows:

the_rect = Rect(200, 100, 150, 40)

So the starting and ending positions of x are 200 and 350, and the starting and ending positions of y-axis are 200 and 240. Why does the y-axis also start at 200? Because the starting point 200 is both the point where the x-axis starts and the point where the y-axis starts. We determine the mouse point like this in the code:

txt = "Pause"
x, y = pygame.mouse.get_pos()
    if pygame.mouse.get_pressed()[0]:
        if x >=200 and x <= 350 and y >= 200 and y <= 240:
            txt = "Clicked

We define txt as the Pause string and determine whether it was clicked by the left mouse button. If so, determine whether the x-axis and y-axis are clicked. If not, change the txt to Clicked.

Then we draw the button box and set the background of the button box to green, then output the text and draw it.

screen.blit(block_surface, (200, 200))
    block_surface.fill([0,20,0])
    text_out(txt)

Draw the block_surface layer at the coordinate point of (200,200), and paint it green, and finally call the text_out function. Since the blit function has been written in text_out, there is no need to blit again.

Let’s take a look at the renderings:

We see a green button placed on the screen, and a white word “Pause” is placed on the button. If the left button of the mouse is clicked on this button, it will change to the word “Clicked”.

At this point, you may ask, why is there no explanation on how to output Chinese?

In this case, there are two solutions for outputting Chinese.

The first is a relatively low-level solution, which is dot matrix rendering based on Chinese. This requires very low-level code operations and is not very efficient, so we will not discuss this solution.

The second is to change the font. When initializing the font, we can download some Chinese fonts from the Internet to try first, or we can use the system font. When using system fonts, we can use SysFont to initialize the font.

fnt = pygame.font.SysFont('Microsoft Yahei',32)

In addition, there is one more place that needs to be modified. We need to add the encoding method at the beginning of the Python code, and add the word u in front of the Chinese text to tell the interpreter that it is Unicode.

# encoding: utf-8
txt = u"pause" 

Let’s take a look at the effect:

At this point, the Chinese output has been completed.

So far, we have finished writing the button part of the UI. As for the menu part, we can also write menu effects in the same way.

As for advanced menu operations, such as clicking to display lower-level menus and hiding menus and other dynamic effects, you can use pictures to create menus and load them. If you use a program to write menu effects, the workload will be too much. If it is in the form of a picture, you only need to load and control the mouse click and draw the submenu.

Summary

Today we learned how to write the UI part and implement text output, mouse movement, and mouse button grabbing. Let’s summarize today’s content.

Regardless of the type of game engine, there are basically three values that need to be controlled for mouse operations, the left button, the middle button and the right button.

Buttons can be drawn in the usual way. If you want to create a better effect, such as a picture frame, you can draw a small frame inside the frame to make it look like it protrudes. This requires you to pay more attention to observing some details, and then analyze how to implement these contents using the simple operations we have talked about.

In 2D games, many game engines do not support Chinese output. If you want to output Chinese, if your engine supports it, you can use system fonts or other Chinese fonts; if the engine does not support it, you can use dot matrix drawing to draw Chinese on the screen. The last way, which is the more extreme way, is to use pictures to directly paste Chinese characters. This method is direct and crude, but the picture resources are too large, and if you want to chat online in the game, there are actually Still, the problem of Chinese output has not been fundamentally solved.