기본 콘텐츠로 건너뛰기

[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. 댓글이 달린걸 확인을 못해서 늦게나마 댓글을 씁니다.

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

      삭제

댓글 쓰기

이 블로그의 인기 게시물

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...

antix linux 업데이트시 GPG Error

 최근에 가장 가벼운 리눅스를 검색해서 antix 리눅스를 설치해서 테스트 해 보고 있습니다. 역시 가볍긴 가볍더군요. 생각보단 패키지 구성도 괜찮아 보였고요.    설치후 좀 써보고 업데이트를 하는데 GPG Error 가 발생했습니다. GPG 키 관련 문제인것 같아서 검색해 보니 antixforum에 답이 있었습니다.  https://www.antixforum.com/forums/topic/how-to-fix-expired-gpg-key-error/   간단히 적어보자면... http://repo.antixlinux.com/bookworm/pool/main/a/antix-archive-keyring/antix-archive-keyring_20019.5.0_all.deb 위 파일을 받은 다음에 터미널에서... sudo dpkg -i antix-archive-keyring_20019.5.0_all.deb 을 실행해서 설치해 주면 됩니다.    그런다음 업데이트를 시도해 보면 잘 됩니다.   

모닝 JA 엔진오일 교환. 보쉬필터 구입

요즘은 주행거리가 1만km 가 안되다보니 1년에 한번씩 엔진오일을 교환하고 있습니다.  1년에 한번이라 그냥 오토큐에서 교환을 했었지만 오토큐의 오일교환 가격이 너무 오른데다가 이젠 보증도 끝났기 때문에 오일과 필터를 구입해서 공임나라로 갔습니다.  > 오일은 kixx g1 fe 1L x 3 을 구입하고 필터는 보쉬제품으로 구입했습니다.   A3003 이 에어필터이고 O0356 이 오일필터 입니다. 기아의 순정부품보단 조금 가격이 저렴합니다.  > 오랜만에 공임나라 갔는데 교환공임이 17000원 이네요. 물가가 오른만큼 오일교환 비용도 예전보다 좀 올랐네요.  필터 품번도 기록해 둘겸 올려 봅니다. ^^;