2014-12-25 7 views
1

Я создаю базовую игру в стиле Понг, используя 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() 

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

+0

Кстати, вы можете уменьшить 'if reset == True:' просто 'if reset:', так как операторы 'if' разрешают непустые, не-Falsey значения для' True' самостоятельно. Это скорее вопрос стиля, но может также рассмотреть возможность изменения 'done = False; if done == False: 'что-то вроде' running = True; if running: 'или даже используя' if True: ', а затем' break'ing из основного цикла on quit. _Это не проблема с вашим кодом, но некоторые советы по стилю, которые вы можете рассмотреть! _ – Augusta

+0

Кроме того, использование 'from import *' немного рискованно, так как оно может выгружать много материала в ваше основное пространство имен. Для небольших программ это не так уж плохо, но позже, если вы имеете дело с большим количеством модулей и функций с большим количеством имен, это может запутать, поскольку «импортные» модули используют имена друг с другом или с вашим собственным. Рассмотрим 'from pygame.locals import pgl' и' if press_keys [pgl.K_UP] '(и т. Д.), Чтобы упорядочить ваши пространства имен. (Обратите внимание, что все, что вы используете из 'pygame.locals', будет нуждаться в префиксе' pgl.', если вы это сделаете! Вам не нужно называть его 'pgl'.) – Augusta

ответ

0

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

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

  1. Определить р # _movey для каждого игрока.
  2. Применить p # _movey к игроку #'s paddle's 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 и удалить петлю 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 (в верхней части окна) и высоты весло.

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

+0

Спасибо, Августа за этот ответ! Некоторое время это происходит в некоторых моих программах, и я сейчас подумал попробовать найти ответ. Меня это раздражало, и я рад узнать ответ. Кроме того, спасибо за советы. Я несколько надеялся получить некоторые вещи, подобные этому, с упоминанием о том, что я новичок в кодировании. Вероятно, я бы выяснил, в конце концов, часть 'if reset == True:', но я даже не думал о том, как работает 'import * ', и что это может быть проблемой позже. Еще раз спасибо. –

+0

@NoahDale Не беспокойтесь! На самом деле я бы не подумал о проблеме с 'from .. import *', если бы сам не видел его здесь, поэтому я рад передать его. – Augusta