搜索
首页后端开发Python教程使用 Python 3 和 Pygame 创建互动游戏:第 4 部分

使用 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中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
可以在Python数组中存储哪些数据类型?可以在Python数组中存储哪些数据类型?Apr 27, 2025 am 12:11 AM

pythonlistscanStoryDatatepe,ArrayModulearRaysStoreOneType,and numpyArraySareSareAraysareSareAraysareSareComputations.1)列出sareversArversAtileButlessMemory-Felide.2)arraymoduleareareMogeMogeNareSaremogeNormogeNoreSoustAta.3)

如果您尝试将错误的数据类型的值存储在Python数组中,该怎么办?如果您尝试将错误的数据类型的值存储在Python数组中,该怎么办?Apr 27, 2025 am 12:10 AM

WhenyouattempttostoreavalueofthewrongdatatypeinaPythonarray,you'llencounteraTypeError.Thisisduetothearraymodule'sstricttypeenforcement,whichrequiresallelementstobeofthesametypeasspecifiedbythetypecode.Forperformancereasons,arraysaremoreefficientthanl

Python标准库的哪一部分是:列表或数组?Python标准库的哪一部分是:列表或数组?Apr 27, 2025 am 12:03 AM

pythonlistsarepartofthestAndArdLibrary,herilearRaysarenot.listsarebuilt-In,多功能,和Rused ForStoringCollections,而EasaraySaraySaraySaraysaraySaraySaraysaraySaraysarrayModuleandleandleandlesscommonlyusedDduetolimitedFunctionalityFunctionalityFunctionality。

您应该检查脚本是否使用错误的Python版本执行?您应该检查脚本是否使用错误的Python版本执行?Apr 27, 2025 am 12:01 AM

ThescriptisrunningwiththewrongPythonversionduetoincorrectdefaultinterpretersettings.Tofixthis:1)CheckthedefaultPythonversionusingpython--versionorpython3--version.2)Usevirtualenvironmentsbycreatingonewithpython3.9-mvenvmyenv,activatingit,andverifying

在Python阵列上可以执行哪些常见操作?在Python阵列上可以执行哪些常见操作?Apr 26, 2025 am 12:22 AM

Pythonarrayssupportvariousoperations:1)Slicingextractssubsets,2)Appending/Extendingaddselements,3)Insertingplaceselementsatspecificpositions,4)Removingdeleteselements,5)Sorting/Reversingchangesorder,and6)Listcomprehensionscreatenewlistsbasedonexistin

在哪些类型的应用程序中,Numpy数组常用?在哪些类型的应用程序中,Numpy数组常用?Apr 26, 2025 am 12:13 AM

NumPyarraysareessentialforapplicationsrequiringefficientnumericalcomputationsanddatamanipulation.Theyarecrucialindatascience,machinelearning,physics,engineering,andfinanceduetotheirabilitytohandlelarge-scaledataefficiently.Forexample,infinancialanaly

您什么时候选择在Python中的列表上使用数组?您什么时候选择在Python中的列表上使用数组?Apr 26, 2025 am 12:12 AM

useanArray.ArarayoveralistinpythonwhendeAlingwithHomeSdata,performance-Caliticalcode,orinterFacingWithCcccode.1)同质性data:arrayssavememorywithtypedelements.2)绩效code-performance-clitionalcode-clitadialcode-critical-clitical-clitical-clitical-clitaine code:araysofferferbetterperperperformenterperformanceformanceformancefornalumericalicalialical.3)

所有列表操作是否由数组支持,反之亦然?为什么或为什么不呢?所有列表操作是否由数组支持,反之亦然?为什么或为什么不呢?Apr 26, 2025 am 12:05 AM

不,notalllistoperationsareSupportedByArrays,andviceversa.1)arraysdonotsupportdynamicoperationslikeappendorinsertwithoutresizing,wheremactssperformance.2)listssdonotguaranteeconeeconeconstanttanttanttanttanttanttanttanttimecomplecomecomecomplecomecomecomecomecomecomplecomectaccesslikearrikearraysodo。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),