본문 바로가기

[Pygame] ✈️ 전투기 슈팅 게임 만들기 5강 | 총알과 적 전투기 충돌 처리

@도마22026. 1. 15. 19:00
728x90


1. 이번 강의 목표

이번 강의에서는 다음을 구현합니다.

  • 총알과 적 전투기의 충돌 판정
  • 충돌하면 총알 제거 + 적 제거
  • 충돌 처리가 꼬이지 않도록 안전하게 삭제 처리

이번 강의가 끝나면 스페이스바로 적을 “처치”할 수 있게 됩니다.


2. 충돌 판정은 Rect로 처리합니다

Pygame에서 충돌은 보통 pygame.Rect를 이용해 처리합니다.
우리는 현재 총알과 적을 리스트로 관리하고 있으므로, 각각을 Rect로 만들어서 겹치는지 확인합니다.

  • 총알 Rect: (bullet_x, bullet_y, bullet_width, bullet_height)
  • 적 Rect: (enemy_x, enemy_y, enemy_width, enemy_height)

Rect끼리 겹치면 colliderect()가 True가 됩니다.


3. 충돌 처리 시 가장 흔한 실수

리스트를 순회하면서 동시에 요소를 지우면 오류가 나거나, 일부가 건너뛰는 문제가 생깁니다.

그래서 이번 강의에서는 아래 방식으로 처리합니다.

  • bullets[:], enemies[:] 처럼 복사본으로 순회
  • 충돌 시 remove()로 제거

초보자에게 가장 안정적인 방식입니다.


4. 총알 ↔ 적 충돌 처리 구현

아래 코드를 게임 루프에서 총알 이동/제거 처리 이후,
그리고 적 이동/제거 처리 이후에 넣어주면 됩니다.

for bullet in bullets[:]:
    bullet_rect = pygame.Rect(bullet[0], bullet[1], bullet_width, bullet_height)

    for enemy in enemies[:]:
        enemy_rect = pygame.Rect(enemy[0], enemy[1], enemy_width, enemy_height)

        if bullet_rect.colliderect(enemy_rect):
            if bullet in bullets:
                bullets.remove(bullet)
            if enemy in enemies:
                enemies.remove(enemy)
            break

여기서 break는 한 발이 여러 적을 동시에 지워버리는 상황을 막기 위한 처리입니다.


5. 실행 결과

이제 실행하면 다음 동작이 됩니다.

  • 적이 위에서 내려옵니다.
  • 총알이 적에 닿으면 적이 사라집니다.
  • 해당 총알도 함께 사라집니다.

다음 강의에서는 여기에 점수 시스템을 붙이면 완성도가 급상승합니다.


6. 마무리

이번 강의에서는 다음을 구현했습니다.

  • Rect 기반 충돌 판정
  • 총알과 적 충돌 시 제거 처리
  • 리스트 삭제 문제 방지

이제부터는 진짜 슈팅게임 느낌이 나기 시작합니다.


전체 코드

더보기
import pygame
import sys
import random

pygame.init()

# 화면 설정
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 640
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Shooting Game")

# FPS 설정
clock = pygame.time.Clock()
FPS = 60

# 플레이어 설정
player_width = 40
player_height = 40
player_x = SCREEN_WIDTH // 2 - player_width // 2
player_y = SCREEN_HEIGHT - player_height - 20
player_speed = 5

# 총알 설정
bullet_width = 5
bullet_height = 15
bullet_speed = 8
bullets = []

# 적 설정
enemy_width = 40
enemy_height = 40
enemy_speed = 3
enemies = []

enemy_spawn_delay = 60
enemy_timer = 0

# 게임 루프
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()

    # 플레이어 이동
    if keys[pygame.K_w]:
        player_y -= player_speed
    if keys[pygame.K_s]:
        player_y += player_speed
    if keys[pygame.K_a]:
        player_x -= player_speed
    if keys[pygame.K_d]:
        player_x += player_speed

    # 화면 밖 제한
    if player_x < 0:
        player_x = 0
    if player_x > SCREEN_WIDTH - player_width:
        player_x = SCREEN_WIDTH - player_width
    if player_y < 0:
        player_y = 0
    if player_y > SCREEN_HEIGHT - player_height:
        player_y = SCREEN_HEIGHT - player_height

    # 총알 발사
    if keys[pygame.K_SPACE]:
        bullet_x = player_x + player_width // 2 - bullet_width // 2
        bullet_y = player_y
        bullets.append([bullet_x, bullet_y])

    # 총알 이동
    for bullet in bullets:
        bullet[1] -= bullet_speed

    # 총알 제거
    for bullet in bullets[:]:
        if bullet[1] < 0:
            bullets.remove(bullet)

    # 적 생성
    enemy_timer += 1
    if enemy_timer >= enemy_spawn_delay:
        enemy_timer = 0
        enemy_x = random.randint(0, SCREEN_WIDTH - enemy_width)
        enemy_y = -enemy_height
        enemies.append([enemy_x, enemy_y])

    # 적 이동
    for enemy in enemies:
        enemy[1] += enemy_speed

    # 적 제거
    for enemy in enemies[:]:
        if enemy[1] > SCREEN_HEIGHT:
            enemies.remove(enemy)

    # ===== 충돌 처리 (총알 vs 적) =====
    for bullet in bullets[:]:
        bullet_rect = pygame.Rect(bullet[0], bullet[1], bullet_width, bullet_height)

        for enemy in enemies[:]:
            enemy_rect = pygame.Rect(enemy[0], enemy[1], enemy_width, enemy_height)

            if bullet_rect.colliderect(enemy_rect):
                if bullet in bullets:
                    bullets.remove(bullet)
                if enemy in enemies:
                    enemies.remove(enemy)
                break

    # 화면 그리기
    screen.fill((0, 0, 0))

    pygame.draw.rect(
        screen,
        (0, 200, 255),
        (player_x, player_y, player_width, player_height)
    )

    for bullet in bullets:
        pygame.draw.rect(
            screen,
            (255, 255, 0),
            (bullet[0], bullet[1], bullet_width, bullet_height)
        )

    for enemy in enemies:
        pygame.draw.rect(
            screen,
            (255, 60, 60),
            (enemy[0], enemy[1], enemy_width, enemy_height)
        )

    pygame.display.update()
    clock.tick(FPS)

pygame.quit()
sys.exit()

728x90
도마2
@도마2 :: 도마의 코드노트

초보자를 위한 코딩 강의를 정리합니다. 파이썬부터 C#, Unity 게임 제작까지 차근차근 기록합니다. — 도마

목차