제작로그 5 - 스프라이트 충돌 체크 기본
스프라이트의 충돌체크 방법은 몇가지가 있는데요. 여기서는 mask 방식의 충돌체크만 설명하겠습니다.
사각형과 원 방식의 충돌체크는 충돌을 판단하는 기준만 다를뿐 기본적으로 비슷한 함수를 사용하기 때문에 뒤에 아주 간단히 설명 하겠습니다.
>
mask 충돌체크를 하기 위해선 기본적으로 이미지를 로딩할때 convert_alpha() 를 사용해야 합니다.
robot_image = pygame.image.load('images/robot.png').convert_alpha()
위의 문장과 같이 이미지를 로드해야 합니다.
>
또 한가지 조건은 sprite 클래스에 mask 란 변수를 만들고 mask 데이터를 넣어 줘야 합니다.
class Robot(pygame.sprite.Sprite):
def __init__(self,img,x,y):
super().__init__()
self.image = img #스프라이트 이미지 surface
self.rect = img.get_rect() #이미지 rect 구해서 저장
self.rect.center = (x,y) #캐릭터 위치좌표
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(img) #충돌체크용 마스크 생성
보통 스프라이트 클래스는 기본적으로 위와 같이 만듭니다. 맨 마지막줄에 보면 pygame.mask.from_surface(img) 문장으로 이미지를 이용해서 mask 를 만들고 있습니다.
>
위의 2가지가 준비되었으면 이제 스프라이트 충돌 함수를 사용할 수 있습니다.
hit_list = pygame.sprite.spritecollide(bullet,robot_list,True,pygame.sprite.collide_mask)
첫번째가 단일 스프라이트, 두번째가 스프라이트 그룹, 세번째 True 는 충돌한 스프라이트를 스프라이트 그룹에서 제거하라는것, 네번째는 충돌체크를 mask 를 이용해서 하라는 것 입니다.
스프라이트 그룹은...
robot_list = pygame.sprite.Group()
robot_list.add(robot1)
robot_list.add(robot2)
robot_list.add(robot3)
방법으로 여러 스프라이트를 추가하는 스프라이트들의 리스트 입니다.
리턴값인 hit_list 는 말 그대로 충돌한 스프라이트들의 리스트 입니다.
위 함수를 사용하면 bullet 스프라이트가 스프라이트 그룹인 robot_list 의 스프라이트들중 하나와 충돌하면 해당 스프라이트는 robot_list 에서 삭제되고 hit_list 로 리턴 됩니다.
저는 이번에 이 함수를 사용하지 않았는데요. 왜냐하면 캐릭터 하나가 2개의 스프라이트로 이루어져 있었기 때문입니다. 게임상의 이유로 스프라이트 그룹을 이용하지 않고 따로 리스트를 이용하는 방법을 선택했습니다.
>
pygame.sprite.collide_mask(bullet,robot)
bullet 과 robot 모두 스프라이트 이고 만일 충돌했으면 True 를 리턴 합니다. 매우 간단하죠. if 문으로 리턴값을 판단해서 충돌후 처리를 하면 됩니다.
넘 간단하지만....끝이고요. 나머지는 사족 입니다.
>
혹시라도 mask 충돌 체크 자체에 대한 이해를 못하는 분을 위해 간단히 설명하자면......
위 이미지는 제가 만든 robot.png 파일을 gimp 에서 읽어온 이미지 입니다. 격자부분은 투명한 부분을 표시하는 겁니다. 녹색으로 된 부분이 캐릭터 이고요. mask 충돌 방법을 이용하면 투명한 부분(격자 부분)은 충돌 체크에서 제외됩니다.
따라서 사각형, 원 충돌체크 같은 특정 범위를 체크 하는 방법에 비해, 정확히 캐릭터의 형태에 따른 충돌 체크를 할 수 있습니다.
위와 같이 배경이 투명한 이미지를 만드는 법은 인터넷에 찾아 보면 나오는데요. 언제 시간나면 저도 한번 포스팅 해 보도록 하겠습니다.
>
사각형, 원으로 체크 하는 방법은 스프라이트 클래스의 rect 값과 radius 값을 기준으로 두 스프라이트의 충돌을 체크 합니다. mask 방식과는 달리 스프라이트에 mask 를 만들 필요가 없으며(당연하지만...) 스프라이트 클래스에 radius 변수가 없다거나 rect 값이 정확하지 않으면 당연히 제대로 작동이 안됩니다.
pygame.sprite.collide_rect(bullet,robot)
pygame.sprite.collide_circle(bullet,robot)
pygame.sprite.spritecollide(bullet,robot_list,True,pygame.sprite.collide_rect)
pygame.sprite.spritecollide(bullet,robot_list,True,pygame.sprite.collide_circle)
위와 같은 방법으로 사용하면 됩니다.
전제 코드를 보여주실 수 있나요?
답글삭제댓글이 달린걸 확인을 못해서 늦게나마 댓글을 씁니다.
삭제소스가 잘 정리되면 올릴 수도 있겠지만 지금 현재의 소스는 올리기 어렵습니다. 수많은 삽질 코드가 같이 있기 때문입니다.
언제 전체 코드를 올릴날이 있을지도 모르겠지만 기약을 드리긴 어렵습니다.