Спрайты не правильно соответствуют границам

Я создаю базовую игру в стиле Понг, используя Pygame, и я дошел до перемещения весла. У меня есть код, который должен препятствовать перемещению весла за края экрана, но если игрок удерживает клавишу перемещения, весло перемещается чуть чуть за край экрана. Как только игрок отпускает ключ, веслочка возвращается назад туда, где он должен остановиться.

Я несколько новичок в 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()

Граничная часть отмечена комментарием.

1 ответ

Проблема в том, что вы исправляете каждую posy paddle не настраивая ее rect одновременно. posx и posy сохраняют расположение вашего sprite-- в этом случае, это center--, но позиция того, что вы видите на экране, определяется rect. Поскольку вы добавляете p#_movey, затем update (который настраивает прямоугольник), затем, наконец, сделайте posy коррекцию для значений вне пределов, rect остается в этом недопустимом местоположении. Поскольку вы скорректировали posy, однако, будущие изменения p#_movey влияют на правильное местоположение, а не на недопустимое значение (поэтому ваш спрайт остается OB до тех пор, пока клавиша перемещения не будет выпущена).

Короче говоря, это то, что происходит:

  1. Определите p # _movey для каждого игрока.
  2. Примените p # _movey к игроку # paddle posy и rect через update.
  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) В качестве альтернативы вы можете запустить проверку границ в методе update paddle и удалить из 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 no need to do it again on the main loop.
 self.rect.center = self.posx, self.posy

... пока ваши границы определяются h (высота экрана, нижняя часть вашего окна) и 0 (верхняя часть окна) и высота весла.

Любое решение должно работать, хотя есть и почти наверняка третьи пути. Надеюсь, это поможет!

licensed under cc by-sa 3.0 with attribution.