반응형

pygame  의 스프라이트 충돌체크에 대해서는 한번 간단하게 정리를 따로 해야 할것 같아 따로 정리를 해 둡니다. 전부 상세하게 적지는 않고 중요한 몇가지만(내가 필요한거만....아마도....?) 정리를 해 봅니다.

 

일단 기본적으로 스프라이트 b1 과 b2 는 다음과 같이 만들었습니다. 변수 정리를 좀 더 하면 보기 좋겠지만 귀찮으니 그냥 합니다.

pic = pygame.image.load("images/ball.png").convert_alpha()
pic2 = pygame.transform.scale(pic,(200,200))
pic3 = pygame.transform.scale(pic,(100,100))

b1 = Block(pic2)
b1.rect.center=(400,400)
b1.radius=100

b2 = Block(pic3)
b2.radius = 50

b1 스프라이트는 (400,400) 위치에 고정되어 있고, b2 스프라이트는 마우스를 클릭하면 그 위치로 이동하는 스프라이트 입니다. 따라서 b2 의 경우는 좌표의 초기 값은 없습니다.

 

1. Rect(사각형) 체크

 

가장 기본적인 방법입니다.

    if(pygame.sprite.collide_rect(b1,b2)):
        print("Hit!")

두 스프라이트가 충돌하는지를 검사해서 충돌하면 bool 값 True 를 리턴합니다. 
사용시 주의할 점은(사실 당연한 겁니다만...) 스프라이트의 rect 에 제대로된 값을 넣어줘야 제대로 작동한다는 점 입니다. 
rect.x ,rect.y 혹은 rect.center 에 제대로된 스프라이트의 위치값이 있어야 제대로 작동합니다.

 

위의 스크린샷을 보면 실제로 두개의 스프라이트는 충돌하지 않았습니다. 하지만 사각형체크 방법은 사각형 형태로 충돌을 체크하기 때문에 위와 같은 상황도 충돌로 판정합니다.

 

2. Circle(원) 체크

    if(pygame.sprite.collide_circle(b1,b2)):
        print("Hit!")

원의 형태로 충돌을 체크 합니다. 위의 이미지와 같이 충돌 체크할 부분이 원인 경우 이 방법을 사용하면 됩니다.

제대로 작동시키기 위해선 sprite 객체에 radius(원의 반지름) 값을 넣어줘야 합니다.

위에 b1,b2 를 보면 radius 값을 넣어준걸 보실 수 있습니다.

 

3. Mask 체크

위의 두가지 방법은 사각형과 원의 특정형태로만 충돌체크가 됩니다. 하지만 스프라이트의 경우 더 다양한 모양이 있을 수 있습니다. 즉 특정 도형의 형태가 아니라 스프라이트의 이미지와 이미지가 직접 충돌하였을때(투명한 알파영역 제외), 이미지와 이미지가 서로 겹쳤을때 충돌로 판정해 줍니다.

 

mask 충돌 체크 방법을 쓰기 위해선 sprite 에 mask 를 만들어 줘야 합니다.

    b1.mask = pygame.mask.from_surface(b1.image)
    b2.mask = pygame.mask.from_surface(b2.image)
    if(pygame.sprite.collide_mask(b1,b2)):
	    print("Hit!")

b1 과 b2 이미지를 이용해서 각각 b1 과 b2 의 스프라이트에 mask 를 만든 다음 스프라이트 b1 과 b2 의 충돌체크를 검사합니다.

 

위에선 이해를 위해 저렇게 mask 값을 생성한것이고 실제코딩시에는 sprite 클래스의 생성자에서 이미지를 넘겨 받으면서 mask 를 만들면 됩니다.

mask 체크 방법을 사용할때 주의할 점이 하나 있는데요. 바로 이미지를 컨버트할때 convert_alpha() 를 사용해야 한다는 것입니다.

pic = pygame.image.load("images/ball.png").convert_alpha()

이미지에 특별히 투명한 부분이 없더라도 위와 같이 convert_alpha() 로 해 주지 않으면 mask 체크가 제대로 작동하지 않더군요. 이것때문에 좀 헤맸습니다. ^^;

 

4. SpriteGroup 과 Sprite 의 충돌체크

pic = []
pic.append(pygame.image.load("images/bb.png").convert_alpha())
pic.append(pygame.image.load("images/gb.png").convert_alpha())
pic.append(pygame.image.load("images/pb.png").convert_alpha())
pic.append(pygame.image.load("images/rb.png").convert_alpha())
pic.append(pygame.image.load("images/yb.png").convert_alpha())

block_list = pygame.sprite.Group()

for j in range(0,5):
    for i in range(1,9):    
        block = Block(pic[random.randrange(5)])
        block.rect.x = i * 91 - 50
        block.rect.y = 50 + 37*j
        block.mask = pygame.mask.from_surface(block.image)
        block_list.add(block)

ball_pic = pygame.image.load("images/ball.png").convert_alpha()
ball_pic = pygame.transform.scale(ball_pic,(15,15))
ball = Block(ball_pic)
ball.rect.center = (410,680)
ball.mask = pygame.mask.from_surface(ball.image)

스프라이트 ball 과 스프라이트그룹 block_list 를 위와 같이 만들어 줬습니다.

 

hit_list = pygame.sprite.spritecollide(ball,block_list,True,pygame.sprite.collide_mask)
for h in hit_list:
    score +=1

위와 같이 충돌체크를 하면 됩니다.

 

리턴값 hit_list 는 충돌한 스프라이트들의 리스트입니다. 각 인자들을 설명하자면...
첫번째가 스프라이트, 두번째가 스프라이트 그룹, 세번째는 충돌한 스프라이트를 스프라이트 그룹에서 제거할것인지, 마지막이 충돌을 체크하는 방법입니다. 위의 예는 mask 를 이용한 체크 방법이고 collide_rect 나 collide_circle 도 가능합니다.

 

이 테스트 프로그램은 공을 마우스로 마음대로 움직일수 있게 했습니다. 마우스로 공을 이동시켜 블럭과 충돌시키면 해당 블럭은 스프라이트 그룹에서 삭제되기 때문에 위와 같이 공과 충돌된 블럭은 사라지게 됩니다.

 

>

 

모든 충돌체크를 다 설명하지는 않았지만, 나머지는 이 정도만 이해하면 이해하기 어렵지 않을거라 생각합니다.

+ Recent posts