Graphical user interface and game development

Graphical user interface and game development

GUI based on the tkinter module
GUI is the abbreviation of Graphical User Interface. Graphical user interface should be familiar to people who have used computers, and there is no need to repeat it here. Python's default GUI development module is tkinter (named Tkinter in previous versions of Python 3). From this name, it can be seen that it is based on Tk. Tk is a toolkit originally designed for Tcl and later ported In many other scripting languages, it provides cross-platform GUI controls. Of course, Tk is not the latest and best choice, nor does it have particularly powerful GUI controls. In fact, developing GUI applications is not Python’s best job. If you really need to use Python to develop GUI applications, wxPython, PyQt, PyGTK, etc. Modules are good choices.

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

  1. Import what we need in 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. Organize the functions of these GUI components through code.
  5. Enter the main event loop (main 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声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量;
        # global关键字用来在函数或其他局部作用域中使用全局变量。
        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()

It should be noted that GUI applications are usually event-driven. The reason to enter the main event loop is to monitor the occurrence of various events such as the mouse and keyboard and execute the corresponding code to process the events, because events will continue to occur. Therefore, such a loop needs to be running and waiting for the next event to occur. On the other hand, Tk provides three layout managers for the placement of controls. The controls can be positioned through the layout manager. The three layout managers are: Placer (the developer provides the size and placement of the control) , Packer (automatically fill the control to the appropriate position) and Grid (place the control based on the grid coordinates), I will not repeat them here.

Using Pygame for game development
Pygame is an open source Python module specifically 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. SDL 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 pay more attention to the function and logic of the game.

Next, let’s complete a simple game. The name of the game is "Big Ball Eats Little Ball". Of course, completing this game is not the point. Learning to use Pygame is not the point. The most important thing is that we have to understand how to use the front in the process. Explain the object-oriented programming, learn to use this programming idea to solve real problems.

Make game window

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

Drawing in the window

You can draw on the window through the function 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 is to set the upper left corner of the screen to the coordinate origin (0, 0), the right direction is the positive direction of the x-axis, and the downward direction is the positive direction of the y-axis. When indicating 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 to see these points. Colors in pygame are represented by the three primary colors of color and light, that is, the RGB value of the color is specified through a tuple or list, and each value is between 0 and 255, because each primary color uses an 8-bit (bit) The three colors are equivalent to a total of 24 bits, which is often referred to as "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()

Load image

If you need to load an image directly onto 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 shown below.

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("xxx.jpg")
    # 在窗口上渲染图像
    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()

Realize animation effects

When it comes to animation, everyone is familiar with it. In fact, to achieve animation effects, the principle itself is very simple. It is to continuously play discontinuous pictures. As long as a certain number of frames per second is reached, then it can be done. A relatively smooth animation effect. If you want to make the ball in the above code move, you can use a variable to indicate the position of the ball, and 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()

Impact checking

Usually there are many objects in a game, and "collision" between these objects is inevitable, such as a shell hitting an airplane, a box hitting the ground, etc. Collision detection is a vital issue that must be dealt with in most games. The sprite (animated sprite) module of pygame provides support for collision detection. Here we will not introduce the functions provided by the sprite module. Because it is very simple to detect whether two small balls collide, just check whether the distance between the center of the sphere is less than the sum of the radii of the two balls. In order to make more small balls, we can process mouse events to create small balls with random colors, sizes and moving speeds at the click of the mouse. Of course, to do this, we can take what we learned before Object-oriented knowledge is applied.

from enum import Enum, unique
from math import sqrt
from random import randint
import pygame


@unique
class Color(Enum):
    """颜色"""

    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)
    GRAY = (242, 242, 242)

    @staticmethod
    def random_color():
        """获得随机颜色"""
        r = randint(0, 255)
        g = randint(0, 255)
        b = randint(0, 255)
        return (r, g, b)

class Ball(object):
    """球"""

    def __init__(self, x, y, radius, sx, sy, color=Color.RED):
        """初始化方法"""
        self.x = x
        self.y = y
        self.radius = radius
        self.sx = sx
        self.sy = sy
        self.color = color
        self.alive = True
        
    def move(self, screen):
        """移动"""
        self.x += self.sx
        self.y += self.sy
        if self.x - self.radius <= 0 or self.x + self.radius >= screen.get_width():
            self.sx = -self.sx
        if self.y - self.radius <= 0 or self.y + self.radius >= screen.get_height():
            self.xy = -self.sy
    
    def eat(self, other):
        """吃其他球"""
        if self.alive and other.alive and self != other:
            dx, dy = self.x - other.x, self.y - other.y
            distance = sqrt(dx ** 2 + dy ** 2)
            if distance < self.radius + other.radius and self.radius > other.radius:
                other.alive = False
                self.radius = self.radius + int(other.radius * 0.146)
    
    def draw(self, screen):
        """在窗口上绘制球"""
        pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, 0)

Event handling

Mouse events can be processed in the event loop, the event type can be determined through the type attribute of the event object, and the position of the mouse click can be obtained through the pos attribute. If you want to handle keyboard events in this place, the approach is similar to handling 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()

Putting the above two pieces of code together, we have completed the 大球吃小球game of " ". To be precise, it is not a game, but we have already told you the basic knowledge of making a small game through this example. With this knowledge, You can start your mini game development journey. In fact, there are still many areas worthy of improvement in the above code. For example, the code for refreshing the window and moving the ball should not be placed in the event loop. After learning the knowledge of multithreading, use a background thread to handle these things. Is a better choice. If we want to get a better user experience, we can also add background music to the game and play sound effects when the ball collides with the ball. Using the pygame mixerand musicmodule, we can do this easily. You can understand this by yourself. Aspect knowledge. In fact, if you want to learn more about pygame, the best tutorial is the official website of pygame. If you have no problems with English, you can go and see it. If you want to develop 3D games, pygameit seems to be powerless, readers who are interested in 3D game development may wish to take a look Panda3D.

Guess you like

Origin blog.csdn.net/weixin_47312141/article/details/108326306