gpt4 book ai didi

python - Pygame sprites - 获取矩形碰撞面

转载 作者:太空宇宙 更新时间:2023-11-03 14:49:49 26 4
gpt4 key购买 nike

我是 pygame 的新手,我正在尝试获取基础知识。我想创建障碍物并检测玩家矩形的哪一侧(代表 Sprite 的碰撞框)与障碍物矩形碰撞。这样我就可以在游戏中创建基本的物理原理。

这就是我所做的:

import pygame

class Player (pygame.sprite.Sprite):
def __init__(self, x=0, y=0, s=100):
super(Player,self).__init__()
self.image = pygame.transform.scale(pygame.image.load("player.png"), (s, s))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y

class Block (pygame.sprite.Sprite):
def __init__(self, x=0, y=500, s=100):
super(Block, self).__init__()
self.image = pygame.transform.scale(pygame.image.load("wall.png"),(s, s))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y

pygame.init()

display = pygame.display.set_mode((800,600))

player = Player()
block = Block()

sprites = pygame.sprite.Group()
living = pygame.sprite.Group()
noliving = pygame.sprite.Group()

sprites.add(player)
sprites.add(block)
living.add(player)
noliving.add(block)

gravity = 1

xCh = 0
yCh = 0

speed = 1

while True:

display.fill((159, 159, 159))

for liv in living:
for noliv in noliving:
if(not pygame.sprite.collide_rect(liv, noliv)):
player.rect.y += gravity

for event in pygame.event.get():
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_ESCAPE):
quit()
elif(event.key == pygame.K_a or event.key == pygame.K_LEFT):
xCh = -speed
elif(event.key == pygame.K_d or event.key == pygame.K_RIGHT):
xCh = speed
elif(event.type == pygame.KEYUP):
xCh = 0
yCh = 0
elif(event.type == pygame.QUIT):
quit()

player.rect.x += xCh

sprites.draw(display)

pygame.display.update()

玩家在接触方 block 时会停止掉落,但如果我向左或向右移动,然后进入方 block ,玩家会直接进入方 block 并从那里停止掉落。我希望玩家无法穿过方 block 。如何做到这一点?

最佳答案

这是您的代码,其中包含建议的修复方法以及其他一些改进建议。

首先要做的事情是:错误在于你从未检查水平移动是否会使方 block 发生碰撞。您只进行了一项检查,并且它实际上仅在发生任何碰撞之后才执行任何操作。在这种情况下,它会阻止“重力”做任何事情。由于您是逐像素更新玩家的,因此碰撞已经发生的事实几乎没有被注意到。解决方法是创建一个检查来验证移动 block 是否可以移动到某个位置,然后才允许它。并且对所有的运动都这样做,而不仅仅是重力运动。

所以,在这里我将解释可以让这个示例代码演变成一个完整游戏的改进。

  1. 消除模块级别的“ float 代码”并将所有内容放入函数内。这对于 future 任何游戏来说都是至关重要的,即使是像开始屏幕(可能还有“再玩一次”屏幕)这样简单的东西。我创建了两个函数,一个用于创 build 置您的游戏环境并创建您的对象以及主要游戏功能。将来你应该进一步分离“设置”阶段,能够创建更多游戏对象或不同的游戏级别。

  2. 重用您的代码。您的 __init__ 方法中的行大部分在两个类之间重复,但对于初始位置和图像名称常量而言。因此,您实际上只需要一个类,并为这些属性传递不同的值。由于您暗示通过使用组等您将拥有两种不同的游戏类型的对象,因此我保留了这两个类,但提取了通用代码。

  3. 帧延迟:您的代码将简单地“尽可能快地”移动 - 这将在不同的计算机中创建不同的游戏速度,并使用 100% 的 CPU - 导致可能的机器速度减慢和过多的电力使用。我添加了 30 毫秒的硬编码暂停 - 这将使您的游戏以接近 30 FPS 的速度移动,并在不同设备上保持速度稳定。所需的另一个更改是重力和速度的硬编码“1”值,这将使玩家一次移动 1 像素,必须更改为更大的值。

  4. 最后但并非最不重要的一点是,“我可以移动到那里”逻辑:它实际上看起来很广泛 - 但会发现检查“这个对象可以移动到那个位置”的简单英语描述很长。该方法本质上是:“存储当前位置”。 “用给定的 x 和 y 位移伪造一个位置”。 “检查我是否与某些东西发生碰撞”。 “如果不是,则恢复之前的位置,并说允许移动”。 “否则,恢复y位置,检查X方向是否有碰撞,如果有,限制水平移动”。 “恢复x位置,将y位置移动所需的量,检查是否发生碰撞。如果是,则限制y方向的移动”。 “如果在 x 或 y 方向上的运动不受限制,则只是组合运动导致碰撞:限制两个方向上的运动是公平的”。 “恢复原始位置,返回允许的 x 和 y 位置更改,以及我们要碰撞的对象”。所有这些逻辑都放在“活的”对象类本身内部,因此可以随时使用,只需在主游戏逻辑中添加一行代码即可。

代码:

import pygame


class GameObject(pygame.sprite.Sprite):
def __init__(self, x=0, y=0, s=100, image=""):
super(GameObject, self).__init__()
if not image:
image = self.image
self.image = pygame.transform.scale(pygame.image.load(image), (s, s))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y


class Player(GameObject):
image = "player.png"

def can_move(self, xCh, yCh, group):
old_pos = self.rect.x, self.rect.y
self.rect.x += xCh
self.rect.y += yCh
collided_with = pygame.sprite.spritecollideany(self, group)
if not collided_with:
# No Collisions at all - allow movement
self.rect.x = old_pos[0]
self.rect.y = old_pos[1]
return True, xCh, yCh, None
# Check if the colision was due to horizontal movement:
self.rect.y = old_pos[1]
if pygame.sprite.spritecollideany(self, group):
# Yes, then indicate horizontal movement should be 0
xCh = 0

# check if collision was due to vertical movement:
self.rect.y += yCh
self.rect.x = old_pos[0]

if pygame.sprite.spritecollideany(self, group):
# Yes - indicate vertical movemnt should be 0
yCh = 0

# if only diagonal movement causes collision, then
# cancel movrment in both axes:
# (i.e. just the diagonal movement would hit the
# obstacle )
if not xCh == 0 and not yCh == 0:
xCh = 0
yCh = 0

self.rect.x = old_pos[0]
self.rect.y = old_pos[1]
return False, xCh, yCh, collided_with



class Block(GameObject):
image = "wall.png"


def setup():
global display, player, living, noliving, gravity, speed, sprites
pygame.init()

display = pygame.display.set_mode((800,600))

player = Player()
block = Block(y=500)

sprites = pygame.sprite.Group()
living = pygame.sprite.Group()
noliving = pygame.sprite.Group()

sprites.add(player)
sprites.add(block)
living.add(player)
noliving.add(block)

gravity = 10
speed = 10


def main():
xCh = 0
yCh = 0
while True:

display.fill((159, 159, 159))

for event in pygame.event.get():
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_ESCAPE):
quit()
elif(event.key == pygame.K_a or event.key == pygame.K_LEFT):
xCh = -speed
elif(event.key == pygame.K_d or event.key == pygame.K_RIGHT):
xCh = speed
elif(event.type == pygame.KEYUP):
xCh = 0
yCh = 0
elif(event.type == pygame.QUIT):
quit()

yCh = gravity

for liv in living:
if liv == player:
check_x_ch = xCh
else:
check_x_ch = 0
can_move, xCh, yCh, obstacle = liv.can_move(xCh, yCh, noliving)

liv.rect.x += xCh
liv.rect.y += yCh

# Do other actions if "can_move" indicates a block was hit...


sprites.draw(display)

pygame.display.update()
pygame.time.delay(30)


setup()
main()

关于python - Pygame sprites - 获取矩形碰撞面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45948995/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com