Python graphical user interface and game development

Posted by Kev0121 on Wed, 22 Dec 2021 18:08:05 +0100

Graphical user interface and game development

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, and there is no need to repeat it here. The default GUI development module for Python is Tkinter (named Tkinter in previous versions of Python 3). From this name, we can see that it is based on Tk. Tk is a toolkit, originally designed for Tcl and later transplanted 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 should Using Python is not the best job. If you really need to use Python to develop GUI applications, wxpthon, PyQt, PyGTK and other modules are good choices.

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

  1. Import what we need in the tkinter module.
  2. Create a top-level window object and use it to host the whole GUI application.
  3. Add GUI components on top-level window objects.
  4. The functions of these GUI components are organized by code.
  5. Enter the 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

    # Modify the text on the label
    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)

    # Confirm exit
    def confirm_to_quit():
        if tkinter.messagebox.askokcancel('reminder', 'Are you sure you want to exit?'):
            top.quit()

    # Create top-level window
    top = tkinter.Tk()
    # Set window size
    top.geometry('240x160')
    # Set window title
    top.title('Games')
    # Create a label object and add it to the top-level window
    label = tkinter.Label(top, text='Hello, world!', font='Arial -32', fg='red')
    label.pack(expand=1)
    # Create a container for buttons
    panel = tkinter.Frame(top)
    # Create a button object to specify which container to add to, and bind the event callback function through the command parameter
    button1 = tkinter.Button(panel, text='modify', command=change_label_text)
    button1.pack(side='left')
    button2 = tkinter.Button(panel, text='sign out', command=confirm_to_quit)
    button2.pack(side='right')
    panel.pack(side='bottom')
    # Turn on the main event loop
    tkinter.mainloop()


if __name__ == '__main__':
    main()

It should be noted that GUI applications are usually event driven. The reason why they want to enter the main event cycle is to listen to the occurrence of various events such as mouse and keyboard and execute the corresponding code to process the events. Because the events will continue to occur, such a cycle needs to be running all the time waiting for the occurrence of the next event. 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 (developers provide the size and placement position of controls), Packer (automatically fill the controls to the appropriate position) and Grid (place controls based on Grid coordinates). They will not be described here.

Game development using Pygame

Pygame is an open source Python module, which is specially used for the development of multimedia applications (such as video games), including support for images, sounds, videos, events, collisions, etc. Pygame is built on SDL SDL is a cross platform multimedia development library, which is implemented in C language. It is widely used in the development of games, simulators, players and so on. Pygame makes game developers no longer bound by the underlying language and can pay more attention to the functions and logic of the game.

Now let's finish a simple little game. The name of the game is "big ball eats small ball". Of course, completing the game is not the key point, and learning to use Pygame is not the key point. The most important thing is that we should experience how to use the object-oriented program design explained earlier in this process and learn to use this programming idea to solve practical problems.

Make game window

import pygame


def main():
    # Initialize the modules in the imported pygame
    pygame.init()
    # Initializes the window for display and sets the window size
    screen = pygame.display.set_mode((800, 600))
    # Sets the title of the current window
    pygame.display.set_caption('Big balls eat small balls')
    running = True
    # Start an event loop to handle the events that occur
    while running:
        # Get events from the message queue and process them
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()

Drawing in a window

You can draw on the window through the function of the draw module in pygame. The graphics you can draw 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 down is the positive direction of the y axis. When indicating the position or setting the size, our default unit is pixel . The so-called pixel is a point on the screen. You can use the image browsing software to try to enlarge a picture several times, and you can see these points. pygame uses color light to represent color Three primary colors Representation, that is, the RGB values of colors are specified through 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 referred to as "24 bit color representation".

import pygame


def main():
    # Initialize the modules in the imported pygame
    pygame.init()
    # Initializes the window for display and sets the window size
    screen = pygame.display.set_mode((800, 600))
    # Sets the title of the current window
    pygame.display.set_caption('Big balls eat small balls')
    # Set the background color of the window (the color is a tuple composed of red, green and blue primary colors)
    screen.fill((242, 242, 242))
    # Draw a circle (parameters are: screen, color, center position, radius, 0 indicates filling circle)
    pygame.draw.circle(screen, (255, 0, 0,), (100, 100), 30, 0)
    # Refresh the current window (the rendering window renders the drawn image)
    pygame.display.flip()
    running = True
    # Start an event loop to handle the events that occur
    while running:
        # Get events from the message queue and process them
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()

Load 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 previously obtained window object. The code is as follows.

import pygame


def main():
    # Initialize the modules in the imported pygame
    pygame.init()
    # Initializes the window for display and sets the window size
    screen = pygame.display.set_mode((800, 600))
    # Sets the title of the current window
    pygame.display.set_caption('Big balls eat small balls')
    # Set the background color of the window (the color is a tuple composed of red, green and blue primary colors)
    screen.fill((255, 255, 255))
    # Loads the image with the specified file name
    ball_image = pygame.image.load('./res/ball.png')
    # Rendering an image on a window
    screen.blit(ball_image, (50, 50))
    # Refresh the current window (the rendering window renders the drawn image)
    pygame.display.flip()
    running = True
    # Start an event loop to handle the events that occur
    while running:
        # Get events from the message queue and process them
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


if __name__ == '__main__':
    main()

Achieve animation effect

Speaking of animation This word is not unfamiliar to everyone. In fact, to achieve animation effect, the principle itself is very simple, that is, play discontinuous pictures continuously. As long as a certain number of frames per second is reached, you can make a relatively smooth animation effect. If you want to move the small ball in the above code, you can use variables to represent the position of the small ball, modify the position of the small ball in the loop, and then refresh the whole window.

import pygame


def main():
    # Initialize the modules in the imported pygame
    pygame.init()
    # Initializes the window for display and sets the window size
    screen = pygame.display.set_mode((800, 600))
    # Sets the title of the current window
    pygame.display.set_caption('Big balls eat small balls')
    # Define variables to represent the position of the ball on the screen
    x, y = 50, 50
    running = True
    # Start an event loop to handle the events that occur
    while running:
        # Get events from the message queue and process them
        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()
        # Change the position of the ball every 50 milliseconds and refresh the window
        pygame.time.delay(50)
        x, y = x + 5, y + 5


if __name__ == '__main__':
    main()

collision detection

Usually, many objects appear in a game, and the "collision" between these objects is inevitable, such as shells hitting aircraft, boxes hitting the ground, etc. Collision detection is a crucial problem that must be dealt with in most games, Sprite of pygame The (animation wizard) module provides support for collision detection. We will not introduce the functions provided by the sprite module for the time being, because it is very simple to detect whether two small balls collide. We only need to check whether the distance between the ball centers is less than the sum of the radii of the two balls. In order to create more small balls, we can click the mouse through the processing of mouse events Create a small ball with random color, size and moving speed. Of course, to do this, we can apply the object-oriented knowledge we learned before.

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

import pygame


@unique
class Color(Enum):
    """colour"""

    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():
        """Get random colors"""
        r = randint(0, 255)
        g = randint(0, 255)
        b = randint(0, 255)
        return (r, g, b)


class Ball(object):
    """ball"""

    def __init__(self, x, y, radius, sx, sy, color=Color.RED):
        """Initialization method"""
        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):
        """move"""
        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.sy = -self.sy

    def eat(self, other):
        """Eat other balls"""
        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):
        """Draw the ball on the window"""
        pygame.draw.circle(screen, self.color,
                           (self.x, self.y), self.radius, 0)

event processing

The mouse event can be processed in the event loop. The event type can be determined through the type attribute of the event object, and then the position of the mouse click can be obtained through the pos attribute. If you want to handle keyboard events, it is also in this place, which is similar to handling mouse events.

def main():
    # Defines the container used to hold all balls
    balls = []
    # Initialize the modules in the imported pygame
    pygame.init()
    # Initializes the window for display and sets the window size
    screen = pygame.display.set_mode((800, 600))
    # Sets the title of the current window
    pygame.display.set_caption('Big balls eat small balls')
    running = True
    # Start an event loop to handle the events that occur
    while running:
        # Get events from the message queue and process them
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            # Code for handling mouse events
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # Get the mouse click position
                x, y = event.pos
                radius = randint(10, 100)
                sx, sy = randint(-10, 10), randint(-10, 10)
                color = Color.random_color()
                # Create a ball at the click of the mouse (random size, speed and color)
                ball = Ball(x, y, radius, sx, sy, color)
                # Add ball to list container
                balls.append(ball)
        screen.fill((255, 255, 255))
        # Take out the ball in the container, draw it if it is not eaten, and remove it if it is eaten
        for ball in balls:
            if ball.alive:
                ball.draw(screen)
            else:
                balls.remove(ball)
        pygame.display.flip()
        # Change the position of the ball every 50 milliseconds and refresh the window
        pygame.time.delay(50)
        for ball in balls:
            ball.move(screen)
            # Check if the ball eats any other balls
            for other in balls:
                ball.eat(other)


if __name__ == '__main__':
    main()

The above two pieces of code are combined, We finished the game of "big ball eats small ball" (as shown in the figure below), it is not exactly 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 small game development journey. In fact, there are many areas worthy of improvement in the above code, such as refreshing the window and moving the ball. The code should not be placed in the 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 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. We can easily do this by using the mixer and music module of pygame. You can understand this knowledge by yourself. In fact, to learn more about pygame, the best tutorial is pygame's official website , if there is nothing wrong with your English, you can go and have a look. If you want to develop 3D games , pygame seems to be inadequate. If you are interested in 3D game development, you might as well take a look Panda3D.

Topics: Python Back-end