2014-12-16 3 views
5

파이썬 프로그래밍 클래스에 우주선 게임을 만들고 싶습니다. sprite.spritecollideany을 사용하여 내 플레이어 스프라이트 spaceshipspriteGroup 그룹의 소행성 스프라이트와 충돌하는지 확인하고 싶습니다. 그러나 내가하는 일과 상관없이 그것은 효과가없는 것 같습니다.파이 게임에 충돌이 발생하지 않습니다. 스프라이트

import pygame 
import random 
pygame.init() 
screen = pygame.display.set_mode((600, 600)) 
pygame.display.set_caption("Asteroids and Spaceships") 

background = pygame.image.load("background.png") 
background = background.convert() 

white = 255,255,255 

#first I make the asteroids with this class. 
class asteroids(pygame.sprite.Sprite): 
    def __init__(self, x, y): 
     pygame.sprite.Sprite.__init__(self) 
     self.x = x 
     self.y = y 
     self.width = 30 
     self.height = 30 

     self.i1 = pygame.image.load("smallasteroid.png") 
     self.i1 = self.i1.convert() 
     self.i1.set_colorkey(white) 
     self.rect = self.i1.get_rect() 
     self.rect.left = x 
     self.rect.top = y 

     self.i2 = pygame.image.load("smallasteroid2.png") 
     self.i2 = self.i2.convert() 
     self.i2.set_colorkey(white) 
     self.rect = self.i2.get_rect() 
     self.rect.left = x 
     self.rect.top = y 

     self.i3 = pygame.image.load("mediumasteroid.png") 
     self.i3 = self.i3.convert() 
     self.i3.set_colorkey(white) 
     self.rect = self.i3.get_rect() 
     self.rect.left = x 
     self.rect.top = y 

     self.current = 0 

    def render(self, image_num): 
     if image_num == 1: 
      self.current = 1 
     if image_num == 2: 
      self.current = 2 
     if image_num == 3: 
      self.current = 3 

    def update(self): 
     if self.current == 1: 
      screen.blit(self.i1, (self.x,self.y)) 
      self.y += random.randint(7,11) 
      if self.y > screen.get_height(): 
       self.y = 0 

     if self.current == 2: 
      screen.blit(self.i2, (self.x,self.y)) 
      self.y += random.randint(5,9) 
      if self.y > screen.get_height(): 
       self.y = 0 

     if self.current == 3: 
      screen.blit(self.i3, (self.x,self.y)) 
      self.y += random.randint(3,6) 
      if self.y > screen.get_height(): 
       self.y = 0 

#and then this is the class for the spaceship 
class spaceship(pygame.sprite.Sprite): 
    def __init__(self, x, y): 
     pygame.sprite.Sprite.__init__(self) 
     self.x = x 
     self.y = y 
     self.width = 40 
     self.height = 60 
     self.image = pygame.image.load("spaceship.png") 
     self.image = self.image.convert() 
     self.image.set_colorkey(white) 
     self.rect = self.image.get_rect() 
     self.rect.left = x 
     self.rect.top = y 

    def update(self): 
     screen.blit(self.image,(self.x,self.y)) 
     if self.y > screen.get_height(): 
      self.y = 0 
     if self.y < screen.get_height()-610: 
      self.y = screen.get_height() 
     if self.x > screen.get_width(): 
      self.x = 0 
     if self.x < screen.get_width()-610: 
      self.x = screen.get_width() 

#main is where I have the game run 
def main(): 
    x_ship, y_ship = 0,0 
    player = spaceship(300,550) 

    spriteGroup = pygame.sprite.Group() #my asteroid sprites are grouped here 

    for i in range(25): 
     image_num = random.randint(0,3) 
     asteroid = asteroids(random.randint(0,500),random.randint(0, 200)) 
     asteroid.render(image_num) 
     spriteGroup.add(asteroid) 

    clock = pygame.time.Clock() 
    keepGoing = True 


    while keepGoing: 
     #this is what I tried to use to check for collisions. I know it's not working but I don't know why. 
     if pygame.sprite.spritecollideany(player,spriteGroup): 
      #the program quits on collision. 
      pygame.quit() 
     for event in pygame.event.get(): 
      if (event.type == pygame.QUIT): 
       keepGoing = False 
      elif event.type == pygame.KEYUP: 
       if event.key == pygame.K_ESCAPE: 
        keepGoing = False 

      if (event.type == pygame.KEYDOWN): 
       if (event.key == pygame.K_LEFT): 
        x_ship = -4 
       if (event.key == pygame.K_RIGHT): 
        x_ship = 4 
       if (event.key == pygame.K_UP): 
        y_ship = -4 
       if (event.key == pygame.K_DOWN): 
        y_ship = 4 

      if (event.type==pygame.KEYUP): 
       if (event.key==pygame.K_LEFT): 
        x_ship = 0 
       if (event.key==pygame.K_RIGHT): 
        x_ship = 0 
       if (event.key==pygame.K_UP): 
        y_ship = 0 
       if (event.key==pygame.K_DOWN): 
        y_ship = 0 

     player.x += x_ship 
     player.y += y_ship 
     screen.blit(background, (0,0)) 
     spriteGroup.clear(screen, background) 
     player.update() 
     spriteGroup.update() 
     clock.tick(50) 
     pygame.display.flip() 

    pygame.quit() 

main() 

충돌이 작동하지 않는 이유를 알아낼 수 없습니다

여기에 코드입니다.

+0

향후 참조 할 수 있도록 시도해 본 내용 중 일부 또는 문제가 있다고 생각되는 부분을 간략하게 언급 할 가치가 있습니다. 자리 표시 자 애셋 (self.i1 = pygame.Surface ((30,30)); self.i1.fill ((255,25,25)) 대신 실제 코드 대신 준비된 코드를 게시 할 수도 있습니다 예를 들어 우리가 쓸모가없는 이미지)를 추가 편집하지 않고 실행할 수 있습니다. 원래 이미지 참조를 그대로 두었으므로 아직 이해할 수 있지만 다음 번에 약간의 도움이 될 것입니다. – Augusta

+0

죄송합니다. 나는 생각하지 않았습니다. 제안 해 주셔서 감사합니다. 다음 번에 내가 게시 할 것을 기억할 것입니다. – alexianFirefly

+0

걱정할 필요가 없습니다! : D 만약 여러분이 코드를 시도해보고 싶다면'소행성 .__ init__ '의'i2'와'i3' 데이터와 같은 중복 코드와 알려진 기능 코드를 지우는 것도 고려할 수 있습니다. 부수적이고 오류와 관련이 없는지 확인하십시오. (가끔은 서둘러야 할 때가 있습니다.) – Augusta

답변

5

귀하의 문제는 spaceshipasteroids 클래스가 모두 update에 자신의 rect의 (자신의 hitboxes)을 개정이다, 그들의 xy 속성은 RECT의 위치에 직접 또는 자동 연결이 없습니다. 두 클래스의 update 함수의 끝에 self.rect.topleft = self.x, self.y과 같은 것을 추가하면 초기화 된 위치에 남아 있지 않고 각자의 직사각형, 즉 사용자의 히트 박스가 이동해야하는 위치로 이동합니다. 케이스는 player에 대해 (300,550)이고 ... 각 소행성에 대한 일부 반 무작위 오프셋 (정확한 위치는 모르겠지만 코드의 실수로 생성 된 코드를 재현 한 후 테스트합니다. 사과합니다. 정확히의 출처를 찾지 못한 경우)

어떤 경우 든 짧은 답변은 각 스프라이트의 x 및 y 위치에 대한 검사가 실행 중이지만 파이 게임을 실제로 해당 위치를 히트 박스에 적용,sprite.spritecollideany은 실제로는 히트 박스가 자체 에 실제로 건드리지 않았으므로 False입니다.

self.rect.topleft = self.x, self.y을 스프라이트 클래스 'update'의 끝에 붙이면 문제가 해결됩니다. 당신이 player.x = x_ship을 대체 할 수있는 대신 update에 상기 코드를 추가하는, 또는

편집

(!이 줄 함수의 끝에와 def update(self) 내에서 가장 낮은 들여 쓰기 수준에 있는지 확인) 및 같은과의 메인 루프에서 player.y = y_ship : 정말 좋은 기회가 이후

while keepGoing: 
    ... 
    player.rect.move_ip(x_ship, y_ship) # move the ship's rect 
    player.x, player.y = player.rect.topleft # update it's x and y, if you use these elsewhere 

    for item in spriteGroup: # update the rects for your asteroid objects 
     item.rect.topleft = item.x, item.y 

가 나는 update -altering 솔루션을 사용하는이 솔루션 w 플레이어가 경기장의 가장자리에 다가 갔을 때 슬픔을 느끼게합니다. 아직도 고려해야 할 또 다른 길입니다.

제안으로, 당신은 property의 있도록 return self.rect.leftreturn self.rect.top 것을 각각 x와 y 값은 당신의 hitbox에서의 좌상에 고정 될 때 <Sprite>.x<Sprite>.y를 재정의 할 수 있습니다. 세터도.

향후 이러한 매개 변수를 어떻게 사용할 지 모르겠습니다. 원하는 경우 완전히 제거하고 가능한 경우 rect '로케이터를 사용할 수 있습니다. 생각할 거리!

주의 사항 :

나는 또한 스프라이트의 xy의 모든 속성은 rect 상자의 왼쪽 상단 지점을 참조 있으리라 믿고있어. 해당 지점이 다른 곳 (예 : 센터)에 있어야한다면,이 코드를 사용하기로 결정한 경우이 코드를 조정해야 할 수도 있습니다.

+0

내가 제안한대로했는데, 이제는 프로그램이 충돌을 일부는 포착 할 수 있지만 항상 그렇지는 않습니다. 왜 잘 모르겠어요. 나는 소행성을 확인하고 다른 경계 (바닥과 오른쪽)를 위해 무언가를 추가하려고 시도했으나 전혀 도움이되지 못했습니다. 어떤 충돌을 감지하기 때문에 무엇을해야할지 모르겠습니다. 때때로 소행성 바로 아래에서 날아갈 수 있고 괜찮을 것입니다. 그러면 소행성에 접근 할 것이고 게임은 마치 소행성과 배는 원래 충돌했다. – alexianFirefly

+0

이상한; 나는 너를 위해 그것을 체크 할 것이다. 'update' 함수 솔루션이나 대안 중 하나를 사용 했습니까? – Augusta

+0

오! 새로운'self.rect.topleft = self.x, self.y' 라인이'update'의 가장 낮은 들여 쓰기 레벨에서 _not_되지 않았습니까? 그렇지 않다면, 아마도'if' 블록의 일부일 것이며'소행성'현재 값 (아마'3')과'우주선 '이 화면의 가장 왼쪽 끝에있을 때만 실행됩니다. (솔루션에 대한 자세한 내용은 지금 수정했습니다.) – Augusta

관련 문제