스푸79 기록 보관소

운석 피하기 게임 개발(10)- 충돌 처리(2) 본문

게임개발

운석 피하기 게임 개발(10)- 충돌 처리(2)

스푸79 2024. 9. 8. 08:00

 
지난 포스트에서 실행한 물리적인 공식을 운석의 충돌에 대입해보자.

    def handle_collision(self, t_velocity, t_mass):        
        final_vel = \
            float((self.mass - t_mass) / (self.mass + t_mass)) * self.velocity + \
            float((2 * t_mass) / (self.mass + t_mass)) * t_velocity
        if final_vel.length() != 0:
            self.target = final_vel.normalize()

 
handle_collision이라는 메서드를 meteor.py에 meteor 클래스에 추가한다.

class Meteor(pygame.sprite.Sprite):
    def __init__(self, s_pos, d_pos, resource, mass):
        super().__init__()
        ... (중략) ...
        self.mass = mass
        self.id = "enemy"

 
그리고  Meteor 클래스의  중량을 주도록 하자. 중량은 size에 따라서 증감이 되도록 Meteor 객체를 생성하는 부분에
중량 생성로직을 추가하자.
main.py 에 spawn_meteor 메서드를 수정하자. 운석의 크기에 따라서 무게를 좀 더 주기 위해 아래와 같이 설정했다.

            meteor_type = random.choice(['A', 'B'])
            meteor_color = random.choice(['1', '2', '3', '4'])
            meteor_size  = random.randint(0, 29)
            r = self.resources.get_meteor(meteor_type, meteor_color)
            
            # 운석의 크기에 따라서 무게를 다르게 설정
            if meteor_size > 20:
                mass = meteor_size * 10
            elif meteor_size > 10:
                mass = meteor_size * 3
            else:
                mass = meteor_size * 1

            meteor = Meteor(pos, d_pos, r[meteor_size], mass)
            self.meteor_sprites.add(meteor)

 
충돌하는 부분에 대해서 로직도 추가하자. 우선 간단하게 pygame 자체 내장된 두 sprites에 대한 충돌 검사 로직인
pygame.sprites.collide_rect를 사용해 봤다.

    def check_collision(self):
        self.collision_check_list.append(self.player_sprites.sprites()[0])
        
        for sprite in self.meteor_sprites.sprites():
            self.collision_check_list.append(sprite)

        for i in range(len(self.collision_check_list)):
            sprite_a = self.collision_check_list[i]
            for j in range(i + 1, len(self.collision_check_list)):
                sprite_b = self.collision_check_list[j]
                if pygame.sprite.collide_rect(sprite_a, sprite_b):
                    sprite_a.handle_collision(sprite_b.velocity, sprite_b.mass)
                    sprite_b.handle_collision(sprite_a.velocity, sprite_a.mass)

        self.collision_check_list.clear()

 
로직 자체는 아주 무식하다.충돌 대상이 되는 모든 sprites를 collision_check_list 배열에 담은 다음
for문을 2번 돌면서 모든 sprites를 한번씩 체크하도록 작성을 했다.
충돌이 발생한 경우, 각 sprites에 handle_collision 을 호출하고 서로의 속도값과 무게를 전달하도록 처리했다.
 
프로그램을 실행해보면 그런데 충돌이 뭔가 어색하다는 것을 느낄 것이다.
뭔가 충돌이 되는 것도 있고 그냥 지나가는 것도 있다.
그리고 부딪치기 전인데 이미 튕겨져 나가는 것도 확인할 수 있을 것이다.
이런 증상이 발생하는 이유는 운석의 회전하는 효과를 주기 위해 이미지를 회전 시켰기 때문에 발생하는 문제이다.
 
아래 붉은색으로 표시된 부분이 바로 아래 sprites의 rect영역이다.
첫번째 운석은 회전이 없는 운석이고 두번째 운석은 45로 회전을 준 운석이다.
눈으로도 두 운석의 rect 영역의 크기가 차이가 나는 걸 알 수가 있다.

 
위의 코드는 rect 영역의 겹치게 되면 충돌로 인지하기 때문에 위와 같은 증상이 발생한다.
또 단순히 두 sprites의 x,y 시작점과 종결점에 대한 충돌 인지로 인해 물리적으로 이해되지 않는 움직임이 발생한다.
 
 
다음 포스트에는 이 문제점을 해결하고
Sweep And Prone이라는 효율적인 충돌 검사 로직을 작성해 보도록 하자.
 
이번 포스트의 소스코드를 첨부한다.

08. collider
0.03MB