Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Mencipta permainan interaktif dengan Python 3 dan Pygame: Bahagian 4

Mencipta permainan interaktif dengan Python 3 dan Pygame: Bahagian 4

WBOY
WBOYasal
2023-08-27 15:01:141271semak imbas

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

Gambaran Keseluruhan

Ini adalah yang keempat dalam siri tutorial lima bahagian tentang membuat permainan dengan Python 3 dan Pygame. Dalam Bahagian Tiga, kami menyelidiki teras Breakout, mempelajari cara mengendalikan acara, melihat kelas Breakout utama dan melihat cara mengalihkan objek permainan yang berbeza.

Dalam bahagian ini, kita akan belajar cara mengesan perlanggaran dan apa yang berlaku apabila bola terkena pelbagai objek seperti dayung, bata, dinding, siling dan lantai. Akhir sekali, kami akan menyemak topik penting UI permainan, khususnya cara membuat menu dengan butang tersuai kami sendiri.

Pengesanan Perlanggaran

Dalam permainan, perkara bertembung antara satu sama lain. Terobosan tidak terkecuali. Selalunya ia adalah bola mengenai sesuatu. Kaedah handle_ball_collision() mempunyai fungsi bersarang bernama intersect(), yang digunakan untuk menguji sama ada bola mengenai objek dan Kedudukan objek dalam objek. Jika bola terlepas objek, kembalikan "Kiri", "Kanan", "Atas", "Bawah", atau "Tiada". 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 rrreee

Pukul bola dengan raket🎜

🎜Apabila bola terkena raket, ia melantun jauh. Jika ia mencecah bahagian atas dayung, ia akan melantun semula tetapi mengekalkan komponen halaju mendatar yang sama. 🎜 🎜Namun, jika terkena satu sisi dayung, ia akan melantun ke sisi lain (kiri atau kanan) dan meneruskan pergerakannya ke bawah sehingga mencecah lantai. Kod ini menggunakan fungsi intersect(). 🎜 rrreee

Mendarat🎜🎜

🎜Apabila raket terlepas bola semasa turun (atau bola terkena bahagian tepi raket), bola akan terus jatuh dan akhirnya terkena lantai. Pada ketika ini, pemain kehilangan nyawa dan bola dicipta semula supaya permainan boleh diteruskan. Permainan berakhir apabila pemain kehabisan nyawa. 🎜 rrreee

Terlanggar siling dan dinding🎜🎜

🎜Apabila bola terkena dinding atau siling, ia hanya melantun semula. 🎜 rrreee

Brick Break🎜🎜

🎜Apabila bola terkena batu bata, ia adalah acara utama dalam Breakout - bata itu hilang, pemain mendapat mata, bola melantun semula dan beberapa perkara lain berlaku (kesan bunyi, dan mungkin kesan khas), saya akan membincangkan itu nanti. 🎜 🎜Untuk menentukan sama ada batu bata dipukul, kod itu menyemak jika ada batu bata yang bersilang dengan bola: 🎜 rrreee 🎜Program menu permainan🎜🎜 🎜 🎜Kebanyakan permainan mempunyai beberapa jenis antara muka pengguna. Breakout mempunyai menu ringkas dengan dua butang, "MAIN" dan "BERHENTI." Menu ini muncul apabila permainan bermula dan hilang apabila pemain mengklik "Mula". Mari lihat cara butang dan menu dilaksanakan dan cara ia disepadukan dengan permainan. 🎜

Buang butang🎜🎜

🎜Pygame tidak mempunyai perpustakaan UI terbina dalam. Terdapat sambungan pihak ketiga, tetapi saya memutuskan untuk membina butang saya sendiri untuk menu. Butang ialah objek permainan dengan tiga keadaan: normal, tuding dan ditekan. Keadaan biasa ialah apabila tetikus tidak berada di atas butang, dan keadaan hover ialah apabila tetikus berada di atas butang tetapi butang kiri tetikus tidak ditekan. Keadaan ditekan ialah apabila tetikus berada di atas butang dan pemain menekan butang kiri tetikus. 🎜 🎜Butang dilaksanakan sebagai segi empat tepat dengan warna latar belakang dan teks dipaparkan padanya. Butang juga menerima fungsi on_click (lalai kepada fungsi noop lambda), yang dipanggil apabila butang diklik. 🎜 rrreee 🎜Butang mengendalikan acara tetikus mereka sendiri dan menukar keadaan dalaman mereka berdasarkan acara ini. Apabila butang ditekan, acara MOUSEBUTTONUP diterima, menunjukkan bahawa pemain mengklik butang tersebut dan fungsi on_click() dipanggil. 🎜 rrreee 🎜Harta back_color yang digunakan untuk melukis segi empat tepat latar belakang sentiasa mengembalikan warna yang sepadan dengan keadaan semasa butang, jadi pemain dapat melihat dengan jelas bahawa butang itu aktif: 🎜 rrreee

Buat menu🎜🎜

Fungsi 🎜create_menu() mencipta menu dengan dua butang yang mengandungi teks "MAIN" dan "BERHENTI". Ia mempunyai dua fungsi bersarang bernama on_play() dan on_quit() yang diberikan kepada butang yang sepadan. Setiap butang ditambahkan pada senarai objek (untuk dilukis) dan medan menu_buttons. 🎜 rrreee 🎜Apabila butang PLAY diklik, on_play() dipanggil, yang mengalih keluar butang daripada senarai objek supaya ia tidak lagi dilukis. Selain itu, medan boolean is_game_running dan start_level yang mencetuskan permulaan permainan ditetapkan kepada True. 🎜 🎜Apabila butang keluar diklik, is_game_running ditetapkan kepada False (menjeda permainan dengan berkesan) dan game_over Tetapkan kepada True untuk mencetuskan urutan permainan terakhir. 🎜 rrreee

Tunjukkan dan sembunyikan menu permainan🎜🎜

🎜Menunjukkan dan menyembunyikan menu adalah tersirat. Menu boleh dilihat apabila butang berada dalam senarai objek apabila ia dialih keluar, ia disembunyikan. Ia semudah itu. 🎜

Anda boleh membuat menu bersarang dengan permukaannya sendiri yang menjadikan subkomponen seperti butang dan kemudian hanya menambah/mengalih keluar komponen menu itu, tetapi menu ringkas ini tidak memerlukannya.

Kesimpulan

Dalam bahagian ini kami merangkumi pengesanan perlanggaran dan perkara yang berlaku apabila bola mengenai pelbagai objek seperti dayung, bata, dinding, siling dan lantai. Selain itu, kami mencipta menu kami sendiri dengan butang tersuai yang menyembunyikan dan menunjukkan berdasarkan arahan.

Dalam bahagian akhir siri ini, kita akan melihat perlawanan akhir, memberi perhatian yang teliti kepada skor dan kehidupan, kesan bunyi dan muzik.

Kemudian kami akan membangunkan sistem kesan khas yang kompleks untuk menambah minat kepada permainan. Akhir sekali, kami membincangkan hala tuju masa hadapan dan potensi penambahbaikan.

Atas ialah kandungan terperinci Mencipta permainan interaktif dengan Python 3 dan Pygame: Bahagian 4. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn