【问题标题】:Sprites not aligning to boundaries correctly精灵未正确对齐边界
【发布时间】:2014-12-25 21:43:02
【问题描述】:

我正在使用 Pygame 创建一个基本的 Pong 风格游戏,并且我已经完成了移动球拍的工作。我有代码可以防止球拍移动到屏幕边缘之外,但是如果玩家按住移动键,球拍会稍微移动到屏幕边缘之外。一旦玩家松开按键,桨叶就会弹回它应该停止的位置。

我对 Python 和一般编码有点陌生,所以我的代码可能不是最整洁或最高效的。虽然这个问题可能根本不会影响游戏玩法,但我想知道它为什么会这样以及如何将其更改为我想要的样子。

我的代码是:

import random
import pygame
from pygame.locals import *
from sys import exit

screen_size = 600, 600
w,h = screen_size
screen = pygame.display.set_mode(screen_size)
clock = pygame.time.Clock()
pic = pygame.image.load

class paddle(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)

        self.pos = pos
        self.posx, self.posy = self.pos
        self.width = 10
        self.height = 100
        self.image = pygame.Surface((self.width, self.height))
        self.image.fill((255,255,255))
        self.rect = pygame.Rect((0,0), self.image.get_size())
        self.speed = 150

    def update(self, mov, tp):
        self.posy += mov * self.speed * tp
        self.rect.center = self.posx, self.posy

class box(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)

        self.pos = pos
        self.posx, self.posy = self.pos
        self.width = 10
        self.height = 10
        self.image = pygame.Surface((self.width, self.height))
        self.image.fill((255,255,255))
        self.rect = pygame.Rect((0,0), self.image.get_size())
        self.speed = 300        

        self.directionx = 0
        self.directiony = 0

    def update(self, mov, tp):
        self.posx += mov[0] * self.speed * tp
        self.posy += mov[1] * self.speed * tp
        self.rect.center = self.posx, self.posy

reset = True

done = False
while done == False:

    if reset == True:
        p1 = paddle((0,0))
        p1 = paddle((20,(h-p1.height)/2))
        p2 = paddle((0,0))
        p2 = paddle((w-20,(h-p2.height)/2))
        paddle_group = pygame.sprite.Group()
        paddle_group.add(p1)
        paddle_group.add(p2)

        ball = box(((w/2)-10,h/2))
        ball_group = pygame.sprite.Group(ball)

        reset = False
    else:
        pass

    time_passed = clock.tick(60)
    time_passed_seconds = time_passed/1000.0

    for event in pygame.event.get():
        if event.type == QUIT:
            done = True

    p1_movey = 0
    p2_movey = 0

    pressed_keys = pygame.key.get_pressed()
    pressed_mb = pygame.mouse.get_pressed()

    if pressed_keys[K_ESCAPE]:
        done = True

    if pressed_keys[K_w]:
        p1_movey = -2
    elif pressed_keys[K_s]:
        p1_movey = +2

    if pressed_keys[K_UP]:
        p2_movey = -2
    elif pressed_keys[K_DOWN]:
        p2_movey = +2

    p1.update(p1_movey, time_passed_seconds)
    p2.update(p2_movey, time_passed_seconds)


# This is where the border check is
    for PADDLE in paddle_group.sprites():

        if PADDLE.posy > h - (PADDLE.height/2):
            PADDLE.posy = h - (PADDLE.height/2)
        elif PADDLE.posy < (PADDLE.height/2):
            PADDLE.posy = (PADDLE.height/2)

    screen.fill((0,0,0))

    paddle_group.draw(screen)

    pygame.display.update()

pygame.quit()

边界部分标有注释。

【问题讨论】:

  • 顺便说一句,您可以将if reset == True: 简化为if reset:,因为if 语句会自行将非空、非Falsey 值解析为True。这更多的是风格问题,但也可以考虑将done = False; if done == False: 更改为running = True; if running: 之类的东西,或者甚至使用if True:,然后在退出时从主循环中使用breaking。 这些不是您的代码的问题,而是您可以考虑的一些样式提示!
  • 除此之外,使用from &lt;module&gt; import * 有点冒险,因为它可以将很多东西转储到您的主命名空间中。对于小程序来说,这还不错,但是稍后,如果您要处理具有很多名称的大量模块和函数,则可能会变得混乱,因为imported 模块彼此或与您自己的模块共享名称。考虑from pygame.locals import pglif pressed_keys[pgl.K_UP](等等)来保持你的命名空间井井有条。 (请注意,如果您这样做,您从 pygame.locals 使用的所有内容都需要前缀 pgl.!您不需要将其命名为“pgl”。)

标签: python-2.7 pygame collision-detection sprite rect


【解决方案1】:

问题在于您正在更正每个paddleposy 而没有同时调整其rectposxposy 存储你的精灵的位置——在这种情况下,它是中心——但是你在屏幕上看到的位置是由rect 决定的。因为您添加了p#_movey,然后添加了update(调整矩形),最后,对越界值进行了posy 更正,rect 仍保留在其无效位置。因为你调整了posy,但是,未来p#_movey 的更改会影响正确的位置,而不是无效的位置(这就是为什么你的精灵在释放移动键之前保持 O.B. 的原因)。

简而言之,就是这样:

  1. 确定每个玩家的 p#_movey。
  2. 通过 update 将 p#_movey 应用到玩家 # 的球拍 posyrect
  3. 调整PADDLE.posy 以使其在每个PADDLE in paddle_group 的范围内,但不要更新PADDLE.rect 以反映调整。 (而且rect 确实需要更新。)
  4. 结束框架。

我能想到的解决方案有两种:

1) 修改您的 for PADDLE in paddle_group.sprites() 循环,以便刷新 PADDLE.rect.center,使其看起来像这样:

  # on the main loop...
for PADDLE in paddle_group.sprites():
    if PADDLE.posy > h - (PADDLE.height/2):
        PADDLE.posy = h - (PADDLE.height/2)
    elif PADDLE.posy < (PADDLE.height/2):
        PADDLE.posy = (PADDLE.height/2)

    PADDLE.rect.center = PADDLE.posx, PADDLE.posy
        ## ^ adding this line, which recenters the rect.

2) 或者,您可以在paddleupdate 方法中运行边界检查,并从主循环中删除for PADDLE in paddle_group.sprites() 循环。 paddle.update(..) 然后看起来像这样:

  # in class paddle(..) ...
def update(self, mov, tp):
    self.posy += mov * self.speed * tp
    self.posy  = max(self.height / 2, min(self.posy, h - (self.height / 2)))
        ## ^ Adding this line, which checks boundaries for posy.
        ## because you're doing it here, there's no need to do it again on the main loop.
    self.rect.center = self.posx, self.posy

...只要您的边界由h(屏幕高度;窗口底部)和0(窗口顶部)和桨的高度定义。

任何一种解决方案都应该有效,尽管几乎可以肯定还有第三种方法。 希望对您有所帮助!

【讨论】:

  • 感谢奥古斯塔的回答!它已经在我的几个程序中发生了一段时间,我刚刚想尝试找到答案。它一直困扰着我一段时间,我很高兴知道答案。另外,谢谢你的提示。我有点希望能得到一些这样的东西,并提到我是编码新手。我可能最终会弄清楚if reset == True: 部分,但我什至从未想过import * 是如何工作的,以后可能会出现问题。再次感谢。
  • @NoahDale 不用担心!如果我自己没有在这里看到from .. import *,我实际上不会想到它的麻烦,所以我很高兴将它传递出去。
猜你喜欢
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
相关资源
最近更新 更多