技術共有

Python グラフィカル ユーザー インターフェイスとゲーム開発_day010

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

tkinterモジュールに基づくGUI

GUI は、Graphical User Interface の略称であり、コンピュータを使用したことがある人なら誰でもよく知っているはずなので、ここで詳しく説明する必要はありません。 Python のデフォルトの GUI 開発モジュールは tkinter (Python 3 より前のバージョンでは Tkinter と呼ばれていました) であることから、Tk は元々 Tcl 用に設計され、後に他の多くのスクリプトに移植されたツールキットであることがわかります。複数の言語に対応し、クロスプラットフォームの GUI コントロールを提供します。もちろん、Tk は最新かつ最良の選択肢ではなく、特に強力な GUI コントロールを備えているわけでもありません。実際、Python を使用して GUI アプリケーションを開発する必要がある場合は、wxPython が最適です。 PyQt、PyGTK などのモジュールが良い選択です。

基本的に、tkinter を使用して GUI アプリケーションを開発するには、次の 5 つの手順が必要です。

  1. 必要なものを tkinter モジュールにインポートします。
  2. 最上位のウィンドウ オブジェクトを作成し、それを使用して GUI アプリケーション全体をホストします。
  3. 最上位のウィンドウ オブジェクトに GUI コンポーネントを追加します。
  4. これらの GUI コンポーネントの機能は、コードによって編成されます。
  5. メインイベントループ(メインループ)に入ります。

次のコードは、tkinter を使用して単純な GUI アプリケーションを作成する方法を示しています。

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', '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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

イベントは引き続き発生するため、GUI アプリケーションは通常、イベント駆動型であることに注意してください。メイン イベント ループに入る理由は、マウスやキーボードなどのさまざまなイベントの発生を監視し、対応するコードを実行してイベントを処理するためです。したがって、このようなループは、次のイベントが発生するまで常に実行する必要があります。一方、Tk は、コントロールを配置するための 3 つのレイアウト マネージャーを提供します。これらの 3 つのレイアウト マネージャーは、次のとおりです。Placer(コントロールのサイズと配置は開発者が提供します)、Packer(コントロールを適切な位置に自動的に配置します) およびGrid(グリッド座標に基づいてコントロールを配置します)、ここでは説明しません。

Pygameを使ったゲーム開発

Pygame は、画像、サウンド、ビデオ、イベント、衝突などのサポートを含む、マルチメディア アプリケーション (ビデオ ゲームなど) の開発に特に使用されるオープン ソースの Python モジュールです。 Pygame は、C 言語で実装されたクロスプラットフォーム マルチメディア開発ライブラリのセットである SDL に基づいて構築されており、ゲーム、シミュレーター、プレーヤーなどの開発に広く使用されています。 Pygame を使用すると、ゲーム開発者は基盤となる言語に拘束されなくなり、ゲームの機能とロジックにさらに集中できるようになります。

さて、ゲームの名前は「Big Ball Eats Small Ball」です。もちろん、最も重要なのは、Pygame の使い方を学ぶことではありません。プロセスの前のステップの使用方法を理解し、オブジェクト指向プログラミングを説明し、このプログラミングのアイデアを実際の問題を解決するために使用する方法を学びます。

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

ウィンドウ内に描画する

pygame の描画モジュールの関数を使用してウィンドウに描画できます。描画できるグラフィックスには、線、長方形、多角形、円、楕円、円弧などが含まれます。スクリーン座標系は、スクリーンの左上隅を座標原点 (0, 0) として設定し、右が x 軸の正の方向、下が y 軸の正の方向であることに注意してください。位置を表現したりサイズを設定したりする場合、デフォルトの単位はピクセルです。いわゆるピクセルは画面上の点であり、画像閲覧ソフトウェアを使用して画像を何度か拡大してこれらの点を確認できます。 pygame での色表現は 3 原色表現方法を使用します。つまり、各原色は 8 ビット (ビット) を使用するため、色の RGB 値はタプルまたはリストを通じて指定されます。各値は 0 ~ 255 です。値を表すには、3 つの色は合計 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

画像の読み込み

画像をウィンドウに直接ロードする必要がある場合は、pygame の画像モジュールの関数を使用して画像をロードし、以前に取得したウィンドウ オブジェクトの 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

アニメーション効果を実現する

アニメーションという言葉については誰もがよく知っていますが、アニメーション効果を実現する原理自体は非常に単純で、1 秒あたりの一定のフレーム数に達する限り、連続しない画像を再生するというものです。よりスムーズなアニメーション効果を生成できます。上記のコードのボールを移動させたい場合は、変数を使用してボールの位置を表し、ループ内のボールの位置を変更してから、ウィンドウ全体を更新します。

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

衝撃チェック

通常、ゲーム内には多くのオブジェクトが存在し、砲弾が飛行機に衝突したり、箱が地面に衝突したりするなど、これらのオブジェクト間の「衝突」は避けられません。衝突検出は、ほとんどのゲームで対処する必要がある重要な問題です。pygame のスプライト (アニメーション化されたスプライト) モジュールは衝突検出をサポートしています。スプライト モジュールが提供する関数は実際には非常に簡単なので、ここでは紹介しません。 2 つの小さなボールが衝突するかどうかを検出します。ボールの中心間の距離が 2 つのボールの半径の合計より小さいかどうかを確認するだけで済みます。さらに小さなボールを作成するには、マウス イベントを処理して、マウスがクリックされた位置にランダムな色、サイズ、移動速度の小さなボールを作成します。これには、適用前に学習した内容を使用できます。オブジェクト指向の知識。

イベント処理

マウス イベントはイベント ループ内で処理できます。イベント タイプはイベント オブジェクトの 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

上記の 2 つのコードを組み合わせると、「大きなボールが小さなボールを食べる」ゲームが完成しました (下の図に示すように)。正確に言うと、これはゲームではありませんが、ゲームを作成するための基本的な知識は習得しました。この例は、この知識があればミニ ゲーム開発を開始できることを示しています。実際、上記のコードには改善すべき点がたくさんあります。たとえば、ウィンドウを更新したり、ボールを移動したりするコードは、マルチスレッドの知識を学んだ後に使用できるようになります。これらを処理するにはバックグラウンド スレッドを使用することをお勧めします。より良いユーザーエクスペリエンスを実現したい場合は、pygame のミキサーと音楽モジュールを使用して、ゲームに BGM を追加したり、ボールが衝突したときに効果音を再生したりすることもできます。これ。実際、pygame について詳しく知りたい場合は、pygame の公式 Web サイトが最適なチュートリアルです。英語に問題がない場合は、行って見てください。 3D ゲームを開発したい場合は、pygame では不十分なようです。3D ゲーム開発に興味のある読者は、Panda3D を検討してみるとよいでしょう。