기본 콘텐츠로 건너뛰기

[pygame] Cannon 게임 프로젝트 5 - 스프라이트 충돌 체크

 제작로그 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)

위와 같은 방법으로 사용하면 됩니다.

댓글

  1. 전제 코드를 보여주실 수 있나요?

    답글삭제
    답글
    1. 댓글이 달린걸 확인을 못해서 늦게나마 댓글을 씁니다.

      소스가 잘 정리되면 올릴 수도 있겠지만 지금 현재의 소스는 올리기 어렵습니다. 수많은 삽질 코드가 같이 있기 때문입니다.
      언제 전체 코드를 올릴날이 있을지도 모르겠지만 기약을 드리긴 어렵습니다.

      삭제

댓글 쓰기

이 블로그의 인기 게시물

드래곤즈 도그마 일본어 음성 패치

드래곤즈 도그마는 캡콤의 오픈월드 RPG 게임으로 액션성이 매우 뛰어난 게임입니다. 이 게임은 원래 콘솔게임이었고 일본어와 일본음성이 존재했으나, 스팀에서 판매되는 PC 판의 경우 일본어는 제외되어 있습니다. 하지만, 능력자들이 음성의 일본어 패치를 제작하여 배포하고 있습니다.   http://www.nexusmods.com/dragonsdogma/mods/108/? 제 경우는 일본어를 거의 못하지만 간단한 게임용 일본어 정도는 알아듣기에 일본어쪽이 게임에 좀더 몰입할 수 있었습니다. 그리고 개인적인 의견으로는 일본어 더빙쪽이 조금 더 잘 되어 있는것 같습니다. 영어가 더 익숙하신 분들은 반대일 수도 있겠지만요. 설치 방법은 다음과 같습니다. 1. 위의 파일을 받아 압축을 푼 후에 스팀 게임 설치 디렉토리로 이동합니다. 2. "SteamApps\common\DDDA" 위치에 모두 복사해 넣으세요. 중복되는 파일은 덮어 씌우시고요. 3. "nativePC\rom" 폴더로 이동하여 patchall.bat 파일을 실행하면 창이 하나 뜨면서 패치가 시작됩니다. 4. 패치완료후에 창을 닫고 게임을 즐기면 됩니다. ^^; 주의 하실 점은, 이 패치는 기존의 영어음성을 덮어 씌우는 형식입니다. 따라서 영어음성으로 다시 바꾸시려면 무결성 검사로 게임을 원본으로 되돌려야 합니다. 음성을 따로 영어/일어 로 선택하여 즐기실 수는 없습니다.

VirtualBox 에 Lubutu 설치

 얼마전에 antix linux 를 설치했었는데 아무래도 늘 이용하던 패키지들이(앱들이) 아니다 보니 이런저런 시간지연(?)이 좀 되어서 천천히 알아가기로 하고 일단 익숙한 xubuntu 를 설치해서 쓰고자 했습니다만... 제가 보통 쓰는 virtualbox 에서 xubuntu 가 설치완료가 안되더군요. 중간에 멈춰버립니다. 부팅해보면 설치는 대충된거 같은데 뭔가 마지막 프로세스를 완료하지 못해서인지 로그인도 안됩니다.  몇번 해보다 안되서 그냥 루분투를 설치했습니다. 루분투는 잘 설치되네요. 루분투는 개인적으론 좀 애매하다고 생각해서....일반적인 데스크탑으로 쓰기엔 xubuntu 정도는 되야 하지 않나 생각합니다.  루분투는 넷북에 설치해 본 바로도 xubuntu 보다 빠르다는 느낌이 없어서 말이죠. 저사양 배포판일텐데.....뭐..넷북이 워낙에 느려서 그럴수도 있지만 antix 리눅스 설치해 본 바로는 lubuntu 보단 낫더라고요. virtualbox에 xubuntu 가 설치가 안되서 예상외로 시간을 좀 까먹었네요. 쩝....

pygame 에서 이미지 회전하는 방법

 pygame 에서 transform.rotate 를 사용해서 이미지를 회전시켜 보면 생각과는 달리 요상하게 회전합니다.    따라서 이를 해결해 보고자 검색해 보다 다음 링크를 찾았습니다. https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame/54714144 위 링크를 보면 파이게임의 이미지 회전이 왜 그렇게 이상한지 알 수 있고 답변하신 분이 blitRotate 라는 함수를 만들어 놓아서 이용할 수 있습니다.  제 소스에 가져와서 테스트를 해 봤는데 제 생각대로 회전 하더군요.  def blitRotate(image, pos, originPos, angle):       #calcaulate the axis aligned bounding box of the rotated image     w, h       = image.get_size()     box        = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]     box_rotate = [p.rotate(angle) for p in box]     min_box    = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])     max_box    = (max(box_rotate, key=lambda p: p[0])[0], max...