Étude Python, notes onze: interface utilisateur graphique et développement de petits jeux

1. Interface graphique basée sur le module tkinter

  • GUI est l'abréviation de Graphical User Interface. L'interface utilisateur graphique ne doit pas être inconnue des personnes qui ont utilisé des ordinateurs, et il n'est pas nécessaire d'entrer dans les détails ici.
  • Le module de développement d'interface graphique par défaut de Python est tkinter (nommé Tkinter dans la version précédente de Python 3). D'après ce nom, on peut voir qu'il est basé sur Tk
    • Tk est une boîte à outils, conçue à l'origine pour Tcl, puis portée dans de nombreux autres langages de script, elle fournit des contrôles d'interface graphique multiplateformes;
    • Bien sûr, Tk n'est pas le choix le plus récent et le meilleur, et il n'y a pas de commandes GUI particulièrement puissantes.
  • En fait, développer des applications GUI n'est pas le meilleur travail de Python.Si vous avez vraiment besoin d'utiliser Python pour développer des applications GUI, des modules tels que wxPython, PyQt, PyGTK, etc. sont tous de bons choix.

  • Fondamentalement, l'utilisation de tkinter pour développer des applications GUI nécessite les 5 étapes suivantes:
    • 1. Importez ce dont nous avons besoin dans le module tkinter.
    • 2. Créez un objet de fenêtre de niveau supérieur et utilisez-le pour héberger l'ensemble de l'application GUI.
    • 3. Ajoutez des composants GUI à l'objet de fenêtre de niveau supérieur.
    • 4. Organisez les fonctions de ces composants GUI via le code.
    • * 5. Entrez dans la boucle d'événements principale (boucle principale).

Paramètres communs du module tkinter (python3)

Cas 1: utiliser tkinter pour créer une application GUI simple

import tkinter
import tkinter.messagebox


def main():
    flag = True

    # 修改标签上的文字
    def change_label_text():
        nonlocal flag  
        """ 
         此处使用:not flag,不能使用False
         如果使用了False,程序就只能执行一次,之后的flag全部都是False
         使得嵌套变量和nonlocal函数失去了意义
        """
        flag = not flag   
        # msg:提示信息
        color, msg = ('red', 'Hello, world!') \
            if flag else ('blue', 'Goodbye, world!') # flag为真设置红色,flag为假设置蓝色
        label.config(text=msg, fg=color)             #  重新配置

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

    # 创建顶层窗口
    top = tkinter.Tk()
    # 设置窗口大小,geometry:几何图形
    top.geometry('240x160') 
    # 设置窗口标题
    top.title('小游戏')
    # 创建标签对象并添加到顶层窗口,bg:背景,fg:前景。
    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()
     
  • Il convient de noter que les applications GUI sont généralement pilotées par les événements. La raison d'entrer dans la boucle d'événements principale est de surveiller l'occurrence de divers événements tels que la souris et le clavier et d'exécuter le code correspondant pour traiter l'événement, car l'événement se poursuivra. Par conséquent, une telle boucle doit être en cours d'exécution et attendre que l'événement suivant se produise.
  • D'autre part, Tk fournit trois gestionnaires de mise en page pour le placement des contrôles. Les contrôles peuvent être positionnés via le gestionnaire de mise en page. Les trois gestionnaires de mise en page sont: Placer (le développeur fournit la taille et le placement du contrôle), Packer (remplit automatiquement le contrôle à la position appropriée) et Grid (placer le contrôle en fonction des coordonnées de la grille)

2. Utilisez Pygame pour le développement de jeux

  • Pygame est un module Python open source spécifiquement pour le développement d'applications multimédias (comme les jeux vidéo), qui inclut la prise en charge d'images, de sons, de vidéos, d'événements, de collisions, etc.
  • Pygame est construit sur la base de SDL. SDL est une bibliothèque de développement multimédia multiplateforme, implémentée en langage C, et est largement utilisée dans le développement de jeux, simulateurs, lecteurs, etc.
  • Pygame permet aux développeurs de jeux de ne plus être liés par le langage sous-jacent et peuvent accorder plus d'attention à la fonction et à la logique du jeu.

Se référer au document chinois pygame

1. pygame.init (): initialise tous les modules pygame importés
2. pygame.display.set_mode (): Initialise une interface prête à être affichée
3. pygame.display.set_caption (): Définit la légende de la fenêtre actuelle
4. pygame.quit (): désinstallez tous les modules pygame importés
5. screen.fill (): Définit la couleur d'arrière-plan de la fenêtre
6. pygame.draw.circle (): dessine un cercle
7. pygame.display.flip (): rafraîchit la fenêtre courante (la fenêtre de rendu présentera l'image dessinée)
8. screen.blit (): place une image au-dessus d'un objet (deux paramètres: image: l'image à placer, position: les coordonnées de l'image)
注意:
	 1.blit()不会更新屏幕,它在缓冲区中绘制图像;
	 2.需要结合update()/flip()将缓冲区发送到视频卡,才能绘制出图像来。
9. pygame.time.delay (10): changez la position de la balle toutes les 10 millisecondes et actualisez la fenêtre

Cas 2: Faire de petits jeux, de grosses boules et de petites boules

La première étape: créer la fenêtre de jeu

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

Étape 2: Dessiner dans la fenêtre

  • Vous pouvez dessiner sur la fenêtre grâce à la fonction du module de dessin dans pygame. Les graphiques pouvant être dessinés comprennent: des lignes, des rectangles, des polygones, des cercles, des ellipses, des arcs, etc.
  • Le système de coordonnées de l'écran consiste à définir le coin supérieur gauche de l'écran sur l'origine des coordonnées (0, 0), à droite la direction positive de l'axe x et vers le bas la direction positive de l'axe y. Lorsque exprimant la position ou définissant la taille, nos unités par défaut sont toutes Est un pixel (un pixel est un point sur l'écran)
  • Les couleurs dans pygame sont représentées par les trois couleurs primaires de couleur et de lumière, c'est-à-dire que la valeur RVB de la couleur est spécifiée via un tuple ou une liste, et chaque valeur est comprise entre 0 et 255, car chaque couleur primaire utilise un 8 bits (bit) Les trois couleurs équivalent à un total de 24 bits, ce qui est souvent appelé «représentation des couleurs 24 bits».
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), 10, 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()

Étape 3: Chargez l'image

  • Si vous avez besoin de charger une image directement sur la fenêtre, vous pouvez utiliser la fonction du module image dans pygame pour charger l'image, puis restituer l'image via la méthode blit de l'objet window obtenu précédemment.
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('D:/360Safe/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()

Étape 4: Réalisez l'effet d'animation

  • En fait, pour obtenir des effets d'animation, le principe lui-même est également très simple, c'est-à-dire la lecture continue d'images discontinues, tant qu'un certain nombre d'images par seconde est atteint, alors un effet d'animation relativement fluide peut être créé.
  • Si vous souhaitez déplacer la balle dans le code ci-dessus, vous pouvez utiliser une variable pour indiquer la position de la balle, modifier la position de la balle dans la boucle, puis actualiser la fenêtre entière.
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(30)
        x, y = x + 5, y + 5


if __name__ == '__main__':
    main()

Étape 5: détection de collision

  • Habituellement, il y a beaucoup d'objets dans un jeu, et la «collision» entre ces objets est inévitable, comme un obus heurtant un avion, une boîte touchant le sol, etc.
  • La détection de collision est un problème crucial qui doit être traité dans la plupart des jeux. Le module sprite de pygame fournit un support pour la détection de collision.
  • Pour détecter si les deux balles entrent en collision, si simple:
    • Vérifiez simplement si la distance entre le centre de la sphère est inférieure à la somme des rayons des deux sphères.
  • Afin de fabriquer plus de petites boules, nous pouvons traiter les événements de souris pour créer de petites boules avec des couleurs, des tailles et des vitesses de déplacement aléatoires à la position du clic de souris, afin que nous puissions appliquer les connaissances orientées objet que nous avons apprises auparavant.
from enum import Enum, unique
from math import sqrt
from random import randint
import tkinter

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.sy = -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)

Étape 6: Gestion des événements

  • Les événements de souris peuvent être traités dans la boucle d'événements et le type d'événement peut être déterminé via l'attribut type de l'objet événement
  • Ensuite, vous pouvez obtenir la position du clic de la souris via l'attribut pos
  • Si vous souhaitez gérer les événements de clavier à cet endroit, l'approche est similaire à la gestion des événements de souris
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)
                
    def confirm_to_quit():
        if tkinter.messagebox.askokcancel('温馨提示', '确定要退出吗?'):
            top.quit()
        
#     # 创建顶层窗口
#     top = tkinter.Tk()
#     # 创建一个装按钮的容器
#     panel = tkinter.Frame(top)
#     # 创建按钮对象 指定添加到哪个容器中 通过command参数绑定事件回调函数
#     button1 = tkinter.Button(panel, text='退出', command=confirm_to_quit)
#     button1.pack(side='right')
#     panel.pack(side='bottom')
#     # 开启主事件循环
#     tkinter.mainloop()

if __name__ == '__main__':
    main()
    
Remarque: Ce blog est basé sur le blog d'apprentissage de Daniel sur GitHub, ainsi que sur ma propre compréhension superficielle, pour enregistrer mon processus d'apprentissage de cette manière.

Lien d'origine GitHub

Je suppose que tu aimes

Origine blog.csdn.net/amyniez/article/details/104588168
conseillé
Classement