使用 Python 3 和 Pygame 創建互動遊戲:第 4 部分

WBOY
發布: 2023-08-27 15:01:14
原創
1276 人瀏覽過

使用 Python 3 和 Pygame 创建互动游戏:第 4 部分

概述

這是有關使用 Python 3 和 Pygame 製作遊戲的五部分教程系列中的第四部分。在第三部分中,我們深入研究了 Breakout 的核心,學習如何處理事件,了解了主要的 Breakout 類,並了解如何移動不同的遊戲物件。

在這一部分中,我們將了解如何偵測碰撞以及當球撞擊各種物體(如槳、磚塊、牆壁、天花板和地板)時會發生什麼。最後,我們將回顧遊戲 UI 的重要主題,特別是如何使用我們自己的自訂按鈕建立選單。

碰撞偵測

在遊戲中,事物會互相碰撞。突破也不例外。大多數情況下是球撞到東西了。 handle_ball_collisions() 方法有一個巢狀函數,名為 intersect(),用來測試球是否擊中物體以及擊中物體的位置。如果球沒有擊中物體,則傳回「左」、「右」、「上」、「下」或「無」。

def handle_ball_collisions(self):
    def intersect(obj, ball):
        edges = dict(
            left=Rect(obj.left, obj.top, 1, obj.height),
            right=Rect(obj.right, obj.top, 1, obj.height),
            top=Rect(obj.left, obj.top, obj.width, 1),
            bottom=Rect(obj.left, obj.bottom, obj.width, 1))
        collisions = set(edge for edge, rect in edges.items() if
                         ball.bounds.colliderect(rect))
        if not collisions:
            return None

        if len(collisions) == 1:
            return list(collisions)[0]

        if 'top' in collisions:
            if ball.centery >= obj.top:
                return 'top'
            if ball.centerx < obj.left:
                return 'left'
            else:
                return 'right'

        if 'bottom' in collisions:
            if ball.centery >= obj.bottom:
                return 'bottom'
            if ball.centerx < obj.left:
                return 'left'
            else:
                return 'right'
登入後複製

用球拍擊球

當球擊中球拍時,它會彈開。如果它擊中槳的頂部,它將彈回來,但保持相同的水平速度分量。

但是,如果它擊中槳的一側,它將彈到另一側(左或右)並繼續向下移動,直到擊中地板。程式碼使用了 intersect 函數()。

# Hit paddle
s = self.ball.speed
edge = intersect(self.paddle, self.ball)
if edge is not None:
    self.sound_effects['paddle_hit'].play()
if edge == 'top':
	speed_x = s[0]
	speed_y = -s[1]
	if self.paddle.moving_left:
		speed_x -= 1
	elif self.paddle.moving_left:
		speed_x += 1
	self.ball.speed = speed_x, speed_y
elif edge in ('left', 'right'):
	self.ball.speed = (-s[0], s[1])
登入後複製

落地

當球拍在下降過程中錯過球(或球擊中球拍的側面)時,球將繼續下落並最終擊中地板。此時,玩家失去了生命,並且球被重新創建,因此遊戲可以繼續。當玩家生命耗盡時,遊戲結束。

# Hit floor
if self.ball.top > c.screen_height:
    self.lives -= 1
	if self.lives == 0:
		self.game_over = True
	else:
		self.create_ball()
登入後複製

撞擊天花板和牆壁

當球撞到牆壁或天花板時,它只會彈回來。

# Hit ceiling
if self.ball.top < 0:
    self.ball.speed = (s[0], -s[1])

# Hit wall
if self.ball.left < 0 or self.ball.right > c.screen_width:
	self.ball.speed = (-s[0], s[1])
登入後複製

打磚塊

當球擊中磚塊時,這是《Breakout》中的一個重大事件- 磚塊消失,玩家獲得一分,球反彈回來,並且會發生一些其他事情(聲音效果,可能還有特殊效果),我稍後再討論。

為了確定磚塊是否被擊中,程式碼會檢查是否有任何磚塊與球相交:

# Hit brick
for brick in self.bricks:
    edge = intersect(brick, self.ball)
	if not edge:
		continue

	self.bricks.remove(brick)
	self.objects.remove(brick)
	self.score += self.points_per_brick

	if edge in ('top', 'bottom'):
		self.ball.speed = (s[0], -s[1])
	else:
		self.ball.speed = (-s[0], s[1])
登入後複製

對遊戲選單進行程式設計

大多數遊戲都有一些使用者介面。 Breakout 有一個簡單的選單,其中有兩個按鈕,分別是「PLAY」和「QUIT」。該選單在遊戲開始時出現,並在玩家點擊「開始」時消失。讓我們看看按鈕和選單是如何實現的以及它們如何與遊戲整合。

製作按鈕

Pygame 沒有內建的 UI 函式庫。有第三方擴展,但我決定為菜單建立自己的按鈕。按鈕是具有三種狀態的遊戲物件:正常、懸停和按下。正常狀態是滑鼠不在按鈕上時,懸停狀態是滑鼠在按鈕上但未按下滑鼠左鍵時。按下狀態是指滑鼠位於按鈕上方且玩家按下滑鼠左鍵時。

該按鈕實作為一個矩形,其上顯示有背景顏色和文字。該按鈕還接收一個 on_click 函數(預設為 noop lambda 函數),該函數在點擊按鈕時被呼叫。

import pygame

from game_object import GameObject
from text_object import TextObject
import config as c


class Button(GameObject):
    def __init__(self, 
                 x, 
                 y, 
                 w, 
                 h, 
                 text, 
                 on_click=lambda x: None, 
                 padding=0):
        super().__init__(x, y, w, h)
        self.state = 'normal'
        self.on_click = on_click

        self.text = TextObject(x + padding, 
                               y + padding, lambda: text, 
                               c.button_text_color, 
                               c.font_name, 
                               c.font_size)

    def draw(self, surface):
        pygame.draw.rect(surface, 
                         self.back_color, 
                         self.bounds)
        self.text.draw(surface)
登入後複製

按鈕處理自己的滑鼠事件並根據這些事件變更其內部狀態。當按鈕處於按下狀態時,收到 MOUSEBUTTONUP 事件,表示玩家點擊了按鈕,並呼叫 on_click() 函數。

def handle_mouse_event(self, type, pos):
    if type == pygame.MOUSEMOTION:
		self.handle_mouse_move(pos)
	elif type == pygame.MOUSEBUTTONDOWN:
		self.handle_mouse_down(pos)
	elif type == pygame.MOUSEBUTTONUP:
		self.handle_mouse_up(pos)

def handle_mouse_move(self, pos):
	if self.bounds.collidepoint(pos):
		if self.state != 'pressed':
			self.state = 'hover'
	else:
		self.state = 'normal'

def handle_mouse_down(self, pos):
	if self.bounds.collidepoint(pos):
		self.state = 'pressed'

def handle_mouse_up(self, pos):
	if self.state == 'pressed':
		self.on_click(self)
		self.state = 'hover'
登入後複製

用於繪製背景矩形的 back_color 屬性始終傳回與按鈕目前狀態相符的顏色,因此玩家可以清楚地看到按鈕處於活動狀態:

@property
def back_color(self):
    return dict(normal=c.button_normal_back_color,
                hover=c.button_hover_back_color,
                pressed=c.button_pressed_back_color)[self.state]
登入後複製

建立選單

create_menu() 函數建立一個帶有兩個按鈕的選單,其中包含文字「PLAY」和「QUIT」。它有兩個巢狀函數,名為 on_play()on_quit() ,它提供給對應的按鈕。每個按鈕都會新增到 objects 清單(待繪製)以及 menu_buttons 欄位。

def create_menu(self):
    for i, (text, handler) in enumerate((('PLAY', on_play), 
                                         ('QUIT', on_quit))):
        b = Button(c.menu_offset_x,
                   c.menu_offset_y + (c.menu_button_h + 5) * i,
                   c.menu_button_w,
                   c.menu_button_h,
                   text,
                   handler,
                   padding=5)
        self.objects.append(b)
        self.menu_buttons.append(b)
        self.mouse_handlers.append(b.handle_mouse_event)
登入後複製

當點擊 PLAY 按鈕時,會呼叫 on_play() ,這會從 objects 清單中刪除按鈕,這樣就不再繪製它們了。此外,觸發遊戲開始的布林欄位 is_game_runningstart_level 設定為 True。

當點擊退出按鈕時,is_game_running 設定為 False (有效暫停遊戲)並且 game_over 設定為 True,觸發最終遊戲序列。

def on_play(button):
    for b in self.menu_buttons:
		self.objects.remove(b)

	self.is_game_running = True
	self.start_level = True

def on_quit(button):
	self.game_over = True
	self.is_game_running = False
登入後複製

顯示和隱藏遊戲選單

顯示和隱藏選單是隱含的。當按鈕位於 objects 清單中時,選單可見;當它們被刪除時,它就被隱藏了。就如此容易。

可以建立一個具有自己的表面的嵌套選單,該表面呈現按鈕等子元件,然後只需新增/刪除該選單元件,但這個簡單的選單不需要它。

結論

在這一部分中,我們介紹了碰撞檢測以及當球撞擊各種物體(例如槳、磚塊、牆壁、天花板和地板)時會發生什麼。此外,我們還創建了自己的選單,其中包含根據命令隱藏和顯示的自訂按鈕。

在本系列的最後一部分中,我們將研究最終遊戲,密切注意得分和生命、音效和音樂。

#然後,我們將開發一套複雜的特效系統,為遊戲增添趣味。最後,我們將討論未來的方向和潛在的改進。

以上是使用 Python 3 和 Pygame 創建互動遊戲:第 4 部分的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板