Python100天打卡-Day10-圖形用戶界面和遊戲開發

Python100天打卡-Day10-圖形用戶界面和遊戲開發
圖形用戶界面和遊戲開發
基於tkinter模塊的GUI
Python默認的GUI開發模塊是tkinter(在Python 3以前的版本中名爲Tkinter)
使用tkinter來開發GUI應用需要以下5個步驟:

導入tkinter模塊中我們需要的東西。
創建一個頂層窗口對象並用它來承載整個GUI應用。
在頂層窗口對象上添加GUI組件。
通過代碼將這些GUI組件的功能組織起來。
進入主事件循環(main loop)。
GUI應用通常是事件驅動式的,之所以要進入主事件循環就是要監聽鼠標、鍵盤等各種事件的發生並執行對應的代碼對事件進行處理,因爲事件會持續的發生,所以需要這樣的一個循環一直運行着等待下一個事件的發生。
另一方面,Tk爲控件的擺放提供了三種佈局管理器,通過佈局管理器可以對控件進行定位,這三種佈局管理器分別是:

Placer(開發者提供控件的大小和擺放位置)
Packer(自動將控件填充到合適的位置)
Grid(基於網格座標來擺放控件)
使用Pygame進行遊戲開發
Pygame是一個開源的Python模塊,專門用於多媒體應用(如電子遊戲)的開發,其中包含對圖像、聲音、視頻、事件、碰撞等的支持。
下面我們來完成一個簡單的小遊戲,遊戲的名字叫“大球吃小球”

製作遊戲窗口
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()

在窗口中繪圖
可以通過pygame中draw模塊的函數在窗口上繪圖,可以繪製的圖形包括:線條、矩形、多邊形、圓、橢圓、圓弧等。
需要說明的是,屏幕座標系是將屏幕左上角設置爲座標原點(0, 0),向右是x軸的正向,向下是y軸的正向
在表示位置或者設置尺寸的時候,我們默認的單位都是像素。所謂像素就是屏幕上的一個點,你可以用瀏覽圖片的軟件試着將一張圖片放大若干倍,就可以看到這些點。
pygame中表示顏色用的是色光三原色表示法,即通過一個元組或列表來指定顏色的RGB值,每個值都在0~255之間,因爲是每種原色都用一個8位(bit)的值來表示,三種顏色相當於一共由24位構成,這也就是常說的“24位顏色表示法”。
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()

加載圖像
如果需要直接加載圖像到窗口上,可以使用pygame中image模塊的函數來加載圖像,再通過之前獲得的窗口對象的blit方法渲染圖像。
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()

實現動畫效果
要實現動畫效果,本身的原理也非常簡單,就是將不連續的圖片連續的播放,只要每秒鐘達到了一定的幀數,那麼就可以做出比較流暢的動畫效果。
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()

碰撞檢測
pygame的sprite(動畫精靈)模塊就提供了對碰撞檢測的支持,這裏我們暫時不介紹sprite模塊提供的功能,因爲要檢測兩個小球有沒有碰撞其實非常簡單,只需要檢查球心的距離有沒有小於兩個球的半徑之和。
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.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)

事件處理
可以在事件循環中對鼠標事件進行處理,通過事件對象的type屬性可以判定事件類型,再通過pos屬性就可以獲得鼠標點擊的位置。在點擊鼠標的位置創建顏色、大小和移動速度都隨機的小球.
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()

其實上面的代碼中還有很多值得改進的地方
比如刷新窗口以及讓球移動起來的代碼並不應該放在事件循環中,等學習了多線程的知識後,用一個後臺線程來處理這些事可能是更好的選擇。
如果希望獲得更好的用戶體驗,我們還可以在遊戲中加入背景音樂以及在球與球發生碰撞時播放音效,利用pygame的mixer和music模塊,我們可以很容易的做到這一點

參考資料:https://github.com/jackfrued/Python-100-Days/blob/master/Day01-15/Day10/圖形用戶界面和遊戲開發.md

作者:wxl1999
來源:CSDN
原文:https://blog.csdn.net/wxl1999/article/details/90300899
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章