Technology Sharing

Python GUI and game development_day010

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

GUI based on tkinter module

GUI is the abbreviation of graphical user interface. Graphical user interface should be familiar to people who have used computers, so there is no need to elaborate on it here. Python's default GUI development module is tkinter (called Tkinter in versions before Python 3). From the name, you can see that it is based on Tk. Tk is a toolkit originally designed for Tcl and later ported to many other scripting languages. It provides cross-platform GUI controls. Of course, Tk is not the latest and best choice, and there is no particularly powerful GUI control. In fact, developing GUI applications is not what Python is best at. If you really need to use Python to develop GUI applications, modules such as wxPython, PyQt, and PyGTK are all good choices.

Basically, using tkinter to develop GUI applications requires the following 5 steps:

  1. Import what we need from the tkinter module.
  2. Create a top-level window object and use it to host the entire GUI application.
  3. Add GUI components to the top-level window object.
  4. The functions of these GUI components are organized through code.
  5. Enter the main event loop.

The following code demonstrates how to use tkinter to make a simple GUI application.

import tkinter
import tkinter.messagebox


def main():
    flag = True

    # 修改标签上的文字
    def change_label_text():
        nonlocal flag
        flag = not flag
        color, msg = ('red', 'Hello, world!')
            if flag else ('blue', 'Goodbye, world!')
        label.config(text=msg, fg=color)

    # 确认退出
    def confirm_to_quit():
        if tkinter.messagebox.askokcancel('温馨提示', '确定要退出吗?'):
            top.quit()

    # 创建顶层窗口
    top = tkinter.Tk()
    # 设置窗口大小
    top.geometry('240x160')
    # 设置窗口标题
    top.title('小游戏')
    # 创建标签对象并添加到顶层窗口
    label = tkinter.Label(top, text='Hello, world!', font='Arial -32', fg='red')
    label.pack(expand=1)
    # 创建一个装按钮的容器
    panel = tkinter.Frame(top)
    # 创建按钮对象 指定添加到哪个容器中 通过command参数绑定事件回调函数
    button1 = tkinter.Button(panel, text='修改', command=change_label_text)
    button1.pack(side='left')
    button2 = tkinter.Button(panel, text='退出', command=confirm_to_quit)
    button2.pack(side='right')
    panel.pack(side='bottom')
    # 开启主事件循环
    tkinter.mainloop()


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

It should be noted that GUI applications are usually event-driven. The reason for entering the main event loop is to monitor the occurrence of various events such as mouse and keyboard and execute the corresponding code to handle the events. Because events will continue to occur, such a loop needs to run all the time to wait for the next event to occur. On the other hand, Tk provides three layout managers for the placement of controls. Controls can be positioned through the layout managers. These three layout managers are:Placer(Developers provide the size and placement of controls),Packer(automatically fills the control to the appropriate position) andGrid(Place controls based on grid coordinates), which will not be described here.

Game Development with Pygame

Pygame is an open source Python module specifically designed for the development of multimedia applications (such as video games), which includes support for images, sounds, videos, events, collisions, etc. Pygame is built on the basis of SDL, which is a cross-platform multimedia development library implemented in C language and is widely used in the development of games, simulators, players, etc. Pygame allows game developers to no longer be bound by the underlying language and can focus more on the functions and logic of the game.

Next, we are going to complete a simple game called "Big Ball Eats Small Ball". Of course, completing this game is not the point, and learning to use Pygame is not the point either. The most important thing is that we must understand how to use the object-oriented programming explained earlier in this process, and learn to use this programming idea to solve real-world problems.

import pygame


def main():
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((800, 600))
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    running = True
    # 开启一个事件循环处理发生的事件
    while running:
        # 从消息队列中获取事件并对事件进行处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Drawing in a Window

You can draw on the window through the functions of the draw module in pygame. The graphics that can be drawn include: lines, rectangles, polygons, circles, ellipses, arcs, etc. It should be noted that the screen coordinate system sets the upper left corner of the screen as the coordinate origin (0, 0), the right is the positive direction of the x-axis, and the downward is the positive direction of the y-axis. When expressing the position or setting the size, our default unit is pixels. The so-called pixel is a point on the screen. You can use the software for browsing pictures to try to enlarge a picture several times, and you can see these points. The three primary colors used to represent colors in pygame are the color light three primary colors, that is, the RGB value of the color is specified by a tuple or list, and each value is between 0 and 255. Because each primary color is represented by an 8-bit value, the three colors are equivalent to a total of 24 bits, which is often called "24-bit color representation".

import pygame


def main():
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((800, 600))
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    # 设置窗口的背景色(颜色是由红绿蓝三原色构成的元组)
    screen.fill((242, 242, 242))
    # 绘制一个圆(参数分别是: 屏幕, 颜色, 圆心位置, 半径, 0表示填充圆)
    pygame.draw.circle(screen, (255, 0, 0,), (100, 100), 30, 0)
    # 刷新当前窗口(渲染窗口将绘制的图像呈现出来)
    pygame.display.flip()
    running = True
    # 开启一个事件循环处理发生的事件
    while running:
        # 从消息队列中获取事件并对事件进行处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Loading an Image

If you need to load the image directly into the window, you can use the function of the image module in pygame to load the image, and then render the image through the blit method of the window object obtained previously. The code is as follows.

import pygame


def main():
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((800, 600))
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    # 设置窗口的背景色(颜色是由红绿蓝三原色构成的元组)
    screen.fill((255, 255, 255))
    # 通过指定的文件名加载图像
    ball_image = pygame.image.load('./res/ball.png')
    # 在窗口上渲染图像
    screen.blit(ball_image, (50, 50))
    # 刷新当前窗口(渲染窗口将绘制的图像呈现出来)
    pygame.display.flip()
    running = True
    # 开启一个事件循环处理发生的事件
    while running:
        # 从消息队列中获取事件并对事件进行处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

Implementing animation effects

Everyone is familiar with the word animation. In fact, the principle of animation is very simple, that is, to play discontinuous pictures continuously. As long as a certain number of frames per second is reached, a smoother animation effect can be achieved. If you want to make the ball in the above code move, you can use a variable to represent the position of the ball, modify the position of the ball in the loop, and then refresh the entire window.

import pygame


def main():
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((800, 600))
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    # 定义变量来表示小球在屏幕上的位置
    x, y = 50, 50
    running = True
    # 开启一个事件循环处理发生的事件
    while running:
        # 从消息队列中获取事件并对事件进行处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        screen.fill((255, 255, 255))
        pygame.draw.circle(screen, (255, 0, 0,), (x, y), 30, 0)
        pygame.display.flip()
        # 每隔50毫秒就改变小球的位置再刷新窗口
        pygame.time.delay(50)
        x, y = x + 5, y + 5


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

Impact checking

Usually there will be many objects in a game, and "collisions" between these objects are inevitable, such as a shell hitting an airplane, a box hitting the ground, etc. Collision detection is a crucial issue that must be dealt with in most games. The sprite (animation sprite) module of pygame provides support for collision detection. We will not introduce the functions provided by the sprite module here for the time being, because it is actually very simple to detect whether two balls collide. You only need to check whether the distance between the centers of the balls is less than the sum of the radii of the two balls. In order to create more balls, we can create balls with random colors, sizes, and moving speeds at the location where the mouse is clicked by processing mouse events. Of course, to do this, we can apply the object-oriented knowledge we learned before.

Event Handling

Mouse events can be processed in the event loop. The event type can be determined through the type property of the event object, and the position of the mouse click can be obtained through the pos property. If you want to process keyboard events, you can also do it here, and the method is similar to processing mouse events.

def main():
    # 定义用来装所有球的容器
    balls = []
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((800, 600))
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    running = True
    # 开启一个事件循环处理发生的事件
    while running:
        # 从消息队列中获取事件并对事件进行处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            # 处理鼠标事件的代码
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # 获得点击鼠标的位置
                x, y = event.pos
                radius = randint(10, 100)
                sx, sy = randint(-10, 10), randint(-10, 10)
                color = Color.random_color()
                # 在点击鼠标的位置创建一个球(大小、速度和颜色随机)
                ball = Ball(x, y, radius, sx, sy, color)
                # 将球添加到列表容器中
                balls.append(ball)
        screen.fill((255, 255, 255))
        # 取出容器中的球 如果没被吃掉就绘制 被吃掉了就移除
        for ball in balls:
            if ball.alive:
                ball.draw(screen)
            else:
                balls.remove(ball)
        pygame.display.flip()
        # 每隔50毫秒就改变球的位置再刷新窗口
        pygame.time.delay(50)
        for ball in balls:
            ball.move(screen)
            # 检查球有没有吃到其他的球
            for other in balls:
                ball.eat(other)


if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

Putting the two codes above together, we have completed the game of "Big Ball Eats Small Ball" (as shown in the figure below). To be precise, it is not a game, but we have told you the basic knowledge of making a small game through this example. With this knowledge, you can start your journey of developing small games. In fact, there are still many things worth improving in the above code, such as refreshing the window and making the ball move should not be placed in the event loop. After learning the knowledge of multithreading, it may be a better choice to use a background thread to handle these things. If you want to get a better user experience, we can also add background music to the game and play sound effects when the balls collide with each other. Using the mixer and music modules of pygame, we can easily do this. You can learn about this knowledge by yourself. In fact, if you want to know more about pygame, the best tutorial is the official website of pygame. If you have no problem with English, you can go and have a look. If you want to develop 3D games, pygame seems to be unable to do it. If you are interested in 3D game development, you may want to take a look at Panda3D.