学到中年的python学习笔记09--图形用户界面和游戏开发练习

目录

 

1. 基于tkinter模块的GUI

2. 使用Pygame进行游戏开发

2.1 制作游戏窗口

2.2 在窗口中绘图

2.3 加载图像

2.4 实现动画效果

2.5 碰撞监测


1. 基于tkinter模块的GUI

使用tkinter开发GUI应用的基本步骤:

导入模块。

创建顶层窗口对象来承载整个GUI应用。

在顶层窗口对象上添加相关组件。

通过逻辑用代码组合组件。

进入主事件循环(mainloop)。

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', 'God, This is god!')
        label.config(text=msg, fg=color)
    
    # 退出窗口
    def window_to_quit():
        if tkinter.messagebox.askokcancel('温馨提示','确认退出?'): # 弹窗返回"True/False"
            window.quit()
    # 创建大的窗口
    window = tkinter.Tk()
    window.title('练习1')
    window.geometry('200x200')

    # 在窗口上创建标签对象
    label = tkinter.Label(window, text='hello, world!', font=('Arial -32'), fg='red')
    label.pack(expand=1)

    button_container = tkinter.Frame(window)
    tkinter.Button(button_container, text='修改', command=change_label_text).pack(side='left')
    tkinter.Button(button_container, text='退出', command=window_to_quit).pack(side='right')

    button_container.pack(side='bottom')    

    window.mainloop()

if __name__ == '__main__':
    main()

GUI通常是事件驱动的,之所以要进入主事循环就是要对鼠标、键盘等各种事件的发生进行监听并执行对应的代码进行响应的处理反应,事件会持续发生,需要一个循环一致运行着对事件的监听等待下一个事件的发生。

在这是一篇博文里的最后讲到Tk的三种窗口部件摆放格式,通过布局管理器可以对控件进行定位,这三种布局管理器分别是:Placer(开发者提供控件的大小和摆放位置)、Packer(自动将控件填充到合适的位置)和Grid(基于网格坐标来摆放控件)。

2. 使用Pygame进行游戏开发

Pygame是一个开源的python模块,专门用于多媒体应用(电子游戏开发)的开发,其中包含对图像、声音、视频、事件、碰撞等的支持。Pygame建立在DSL的基础上,SDL是一套跨平台的多媒体开发库,用C语言实现,被广泛的应用于游戏、模拟器、播放器等等。

跟着大佬学习,其实工具不重要主要是实现代码的逻辑很重要。

代码演示

2.1 制作游戏窗口

import pygame

def main():
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化显示的窗口和设置窗口尺寸
    screen = pygame.display.set_mode((600, 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()

2.2 在窗口中绘图

本次实例主要使用pygame中的draw模块的函数在窗口上绘图,根据你想要的图像绘图实现的方法有很多,需要注意的是建立的窗口为一个在二维的平面坐标系也就是坐标原点(0,0)在左上角的左边轴,也就是数学课上理解的第四象限,只不过向下的y轴为正向坐标,在表示位置或者设置尺寸的时候,默认的单位都是像素,像素也就是存活在坐标轴上的一个点。pygame中颜色的表示使用的是色光三原色表示法,即通过一个元组或列表来指定颜色的RGB值,每个值都是在0~255之间,每一种原色都用一个8位(bit)的值表示,三种颜色相当于一共由24位构成,这就是常说的“24位颜色表示法”。

import pygame

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 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()

2.3 加载图像

如果需要为窗口设置背景图片,可以使用pygame中的image模块的函数来加载本地图片,然后通过之前获得的窗口对象blit方法渲染图像。

import pygame

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption('打球吃小球')

    screen.fill((255, 255, 255))
    # 通过指定的文件名加载图片
    ball_image = pygame.image.load('D:/Microsoft VS Code/pythonProject/Day1-15/image/timg.jpg')
    # 在窗口渲染图片 括号内的参数是图片的位置
    screen.blit(ball_image, (1, 1))
    # 刷新当前窗口(渲染窗口将绘制的图像显示出来)
    pygame.display.flip()

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
if __name__ == '__main__':
    main()

2.4 实现动画效果

学过前端的同学应该清楚,如果想要更好的展示一个前端的吸引之处在于使静态的页面呈现动态的效果,比如网站首页的轮播图。记得以前学习前段时老师将他的网页动态轮播效果图展示出来的时候是多么的吃惊,其实要实现动画效果也是很简单的,也就是将很多图片连续不断的切换,要是每秒达到一定的帧数,那就可以做出流畅的动画效果。那如何上2.3中的小球动起来呢?

import pygame

def main():
    # 初始化导入的pygame模块
    pygame.init()
    screen = pygame.display.set_mode((600, 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毫秒就将小球的圆心坐标加5
        pygame.time.delay(50)
        x, y = x + 5, y + 5


if __name__ == '__main__':
    main()

2.5 碰撞监测

游戏分为很多类,但主要的游戏都是以竞争、格斗为主。一个游戏会有很多的对象,而这些对象必须要设计“碰撞”,比如一个技能命中目标,两个任务互相平A等等。碰撞监测在目前主流的游戏内都是一个很重要的一环,pygame的sprite(动画精灵)模块就提供了对碰撞检测的支持,要想详细的了解该模块请自行百度,因为本人学习python的目的主要不是写游戏,只是课程存在,也可以通过该模块学习更多的知识和锻炼编程的逻辑。目前的学习本人觉得首要的信念就是要相信互联网上的大佬有很多,要想学习首先要学会找到这些资源。在如上文这类简单的平面游戏只需要检测球心的距离是否大于两球的半径只有即可。

首先需要画板,然后需要小球,主要是对小球的控制,要控制小球的颜色和大小,以及移动的速度。

大球吃小球的完整代码如下:

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 randint_color():
        '''获得随机颜色'''
        r = randint(0, 255)
        g = randint(0, 255)
        b = randint(0, 255)
        return (r, g, b)

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

def main():
    # 定义容器
    balls = []
    # 初始化pygame模块
    pygame.init()
    screen = pygame.display.set_mode((600,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, 20)
                sx, sy = randint(-10, 10), randint(-10, 10)
                color = Color.randint_color()
                ball = ball_1(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()

 

你可能感兴趣的:(高级编程语言,python)