8월27일

Win Cha·2026년 8월 28일

게임은 또 시작되고..

1. 현재까지의 코드 개발 현황

import pygame
import random

1. 초기화 -> 변수의 구성

pygame.init()

2. 게임 화면 설정 -> 고정값

size = [400, 900]
screen = pygame.display.set_mode(size)

title = "pyGameExample"
pygame.display.set_caption(title)

3. 게임 내에서의 설정 -> 변수, 함수로 처리

clock = pygame.time.Clock()

color1 = (160, 250, 208)
color2 = (191, 234, 255)
black_color = (0,0,0)
white_color = (255,255,255)

k = 0

class Img_Object:
def init(self):
self.x = 0
self.y = 0

def add_Img(self, address):
    if address[-3:] == "png":
        self.img = pygame.image.load(address).convert_alpha()
    else:
        self.img = pygame.image.load(address)

def change_size(self, width, height):
    self.img = pygame.transform.scale(self.img, (width, height))
    self.width, self.height = self.img.get_size()

def show_Img(self):
    screen.blit(self.img,(self.x, self.y))

a.x - b.width <= b.x <= a.x + a.width

a.y - b.height <= b.y <= a.y + a.height

def is_crash(a, b):
if (a.x - b.width <= b.x) and (b.x <= a.x + a.width):
if (a.y - b.height <= b.y) and (b.y <= a.y + a.height):
print("CRASH!!!!")
return True
else:
return False
else:
return False

hero = Img_Object()
hero.add_Img("C:/Users/201/Pictures/pyGame/hero1.png")
hero.change_size(80,80)
hero.x = round(size[0] / 2) - round(hero.width / 2)
hero.y = size[1] - hero.height - 70
hero.move = 5

left_move = False
right_move = False
space_on = False

missile_list = []
enemy_list = []

4. 메인 이벤트

system_exit = 0
while system_exit == 0:

#   4-1. FPS(Frames per Sec) 설정
clock.tick(60)
#   4-2. 입력(키보드, 마우스)의 감지
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        system_exit = 1
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            left_move = True
        if event.key == pygame.K_RIGHT:
            right_move = True
        if event.key == pygame.K_SPACE:
            space_on = True
            k = 0
    elif event.type == pygame.KEYUP:
        if event.key == pygame.K_LEFT:
            left_move = False
        if event.key == pygame.K_RIGHT:
            right_move = False
        if event.key == pygame.K_SPACE:
            space_on = False
#   4-3. 입력, 시간에 따른 변화

if left_move == True:
    hero.x -= hero.move
    if hero.x <= 0:
        hero.x = 0
elif right_move == True:
    hero.x += hero.move
    if hero.x >= size[0] - hero.width:
        hero.x = size[0] - hero.width

if space_on == True and k % 6 == 0:
    missile = Img_Object()
    missile.add_Img("C:/Users/201/Pictures/pyGame/missile.png")
    missile.change_size(25,50)
    missile.x = hero.x + (hero.width / 2) - (missile.width / 2)
    missile.y = hero.y - missile.height - 15
    missile.move = 5
    missile_list.append(missile)
    print(missile_list)

k += 1

delete_missile_list = []                             # 지울 애 메모할 공간

for i in range(len(missile_list)):
    m = missile_list[i]
    m.y -= m.move
    if m.y <= -m.height:
        delete_missile_list.append(m)

delete_missile_list.reverse()

for d in range(len(delete_missile_list)):
    print(missile_list)
    del missile_list[d]
    print(missile_list)
    print("미사일 소멸!")

if random.random() >= 0.98:
    enemy = Img_Object()
    enemy.add_Img("C:/Users/201/Pictures/pyGame/enemy.png")
    enemy.change_size(40,40)
    enemy.x = random.randrange(0 + round(hero.width/2), size[0] - enemy.width - round(hero.width/2))
    enemy.y = 50
    enemy.move = 4
    enemy_list.append(enemy)

delete_enemy_list = []

for i in range(len(enemy_list)):
    e = enemy_list[i]
    e.y += e.move
    if e.y >= size[1]:
        delete_enemy_list.append(e)

delete_enemy_list.reverse()

for d in range(len(delete_enemy_list)):
    print(enemy_list)
    del enemy_list[d]
    print(enemy_list)
    print("적 소멸!")

delete_crash_missile_list = []
delete_crash_enemy_list = []

for i in range(len(missile_list)):
    for j in range(len(enemy_list)):
        m = missile_list[i]
        e = enemy_list[j]

        if is_crash(m, e) == True:
            delete_crash_missile_list.append(m)
            delete_crash_enemy_list.append(e)

delete_crash_missile_list = list(set(delete_crash_missile_list))
delete_crash_enemy_list = list(set(delete_crash_enemy_list))
delete_crash_missile_list.reverse()
delete_crash_enemy_list.reverse()

for d in range(len(delete_crash_missile_list)):
    del missile_list[d]
    print("적 충돌 소멸!")

for d in range(len(delete_crash_enemy_list)):
    del enemy_list[d]
    print("미사일 충돌 소멸!")

#   4-4. 전사작업(그리기)

screen.fill(black_color)

hero.show_Img()

for m in missile_list:
    m.show_Img()

for e in enemy_list:
    e.show_Img()

#   4-5. 업데이트
pygame.display.flip()

5. 종료(x버튼을 클릭해서 종료, game over 종료)

pygame.quit()

위 프로그램의 문제점 해결

문제점 1 : 적들이 간헐적으로 죽거나 내 미사일에 부딪쳐도 죽지 않는 문제가 발생했음.

1) 문제 원인 분석 : 적을 지우는 로직의 코드가 리스트를 활용한 방식인데, 제거 로직은 아래와 같음
for d in range(len(delete_crash_enemy_list)):
del enemy_list[d]

*여기서 문제는 지울 적의 리스트는 잘 만들어졌지만 정작 지우는 방식은 리스트에서 있는 적들을 순차적으로 지원 것으로 미사일에 맞은 적을 제대로 지우지 못하고 있음
2) 조치 및 수정 :

#[수정] 미사일 맞은 적을 정확히 찾아 지우기 (엉뚱한 적이 죽는 현상 해결!)
for e in delete_crash_enemy_list:
if e in enemy_list:
enemy_list.remove(e)
print("미사일 맞은 적 소멸!")

문제점 2 : 적들과 부딪친 내 미사일도 사라지지 않는 문제가 발생했음.

1) 문제 원인 분석 : 위 적을 지우는 로직과 동일한 문제로, 기존 제거 로직은 아래와 같음
기존 코드의 del missile_list[d]는 맞춘 미사일이 아니라 맨 뒤에서 발사된 미사일을 지우는 버그가 있었습니다.

2) 조치 및 수정 :
#[수정] 충돌한 미사일 정확히 찾아 지우기
for m in delete_crash_missile_list:
if m in missile_list:
missile_list.remove(m)
print("적 충돌 미사일 소멸!")enemy_list.remove(e)
print("미사일 맞은 적 소멸!")

코드 다시 복습하기!!!!!!

파이썬에서 리스트 안의 데이터를 지울 때 사용하는 del과 remove()는 아주 비슷해 보이지만, 지우는 방식(기준)이 완전히 다릅니다.
앞서 파이게임(Pygame) 코드에서 "엉뚱한 적이 죽는 버그"가 발생했던 이유도 바로 이 둘의 차이 때문이었습니다. 알기 쉽게 비교해 드릴게요!
1. del : "위치(순서)"를 기준으로 지우기del은 "리스트의 몇 번째 자리에 있는 녀석을 지워!"라고 명령할 때 사용합니다. 안에 무슨 데이터가 들어있는지는 관심이 없고, 오직 '방 번호(인덱스)'만 봅니다.사용법: del 리스트이름[인덱스]특징: 여러 개를 한 번에 지우는 것(슬라이싱)도 가능합니다.Python과일바구니 = ['사과', '바나나', '포도', '수박']

1번 방(두 번째 자리)에 있는 과일을 지워라!

del 과일바구니[1]
print(과일바구니) # 결과: ['사과', '포도', '수박'] (바나나가 지워짐)

여러 개를 한꺼번에 지울 수도 있습니다.

del 과일바구니[1:3] # 1번 방부터 2번 방까지 지워라!
🚨 주의할 점: 리스트에 없는 방 번호를 지우라고 하면 IndexError가 발생하며 프로그램이 튕깁니다.2. remove() : "이름(값)"을 기준으로 지우기remove()는 "방 번호는 모르겠고, 이름이 '사과'인 녀석을 찾아서 지워!"라고 명령할 때 사용합니다. 위치(인덱스)가 아니라 '실제 데이터 값'을 찾아서 지웁니다.사용법: 리스트이름.remove(지울 값)특징: 똑같은 값이 여러 개 있다면 가장 앞에 있는 1개만 지웁니다.Python과일바구니 = ['사과', '바나나', '포도', '바나나']

'바나나'라는 값을 찾아서 지워라!

과일바구니.remove('바나나')
print(과일바구니) # 결과: ['사과', '포도', '바나나']

(앞에 있던 바나나만 지워지고 뒤에 있는 바나나는 남음)

주의할 점: 바구니 안에 없는 값을 지우라고 하면 ValueError가 발생합니다. 그래서 보통 if '바나나' in 과일바구니: 처럼 값이 있는지 먼저 확인하고 지우는 것이 안전합니다.
한눈에 보는 핵심 차이점구분del 명령어remove() 함수지우는 기준위치 (Index)값 (Value)코드 형태del list[0]list.remove('사과')무엇을 모를 때 쓰나요?안에 무슨 값이 들었는지 모를 때몇 번째 방에 있는지 모를 때여러 개 삭제가능 (슬라이싱 [0:2])불가능 (한 번에 1개씩만 삭제)에러 종류방 번호가 틀리면 IndexError값이 없으면 ValueError 이전 게임 코드에서 버그가 났던 이유이전 코드에서는 화면 밖으로 나간 적을 지우려고 아래처럼 코드를 짰었습니다.
Pythonfor d in range(len(delete_enemy_list)):
del enemy_list[d] # <- 버그 발생 지점
여기서 d는 지워야 할 적 자체가 아니라 0, 1, 2라는 순서(방 번호)입니다. 만약 3번째 방에 있는 적이 총알에 맞았더라도, d가 0부터 시작하기 때문에 컴퓨터는 무조건 del enemy_list[0](맨 앞의 적)을 지워버리는 대참사가 일어난 것입니다.그래서 이를 "순서 상관없이 방금 총알에 맞은 바로 그 적 객체(e)를 찾아서 지워라!"라는 의미로 enemy_list.remove(e)로 바꾼 것입니다.

이 코드는 파이썬을 이용해 수학의 '반지름이 1인 원'을 그래프로 그리는 프로그램입니다.

원의 방정식인 x2+y2=1x^2 + y^2 = 1을 yy에 대해 풀면 y=±1−x2y = \pm\sqrt{1 - x^2}이 되는데, 이 수학 공식을 파이썬 코드로 그대로 옮겨서 수많은 점을 찍어 원을 만드는 원리입니다.

초보자분들도 이해하기 쉽도록 코드 한 줄 한 줄에 자세한 주석을 달고, 아래에 전체적인 흐름을 설명해 드릴게요!


📝 주석이 추가된 코드

import matplotlib.pyplot as plt  # 그래프를 그리기 위한 도구(라이브러리)를 가져옵니다.
import math  # 수학 계산(루트 등)을 하기 위한 도구(라이브러리)를 가져옵니다.

x_list = []  # x 좌표 점들을 모아둘 빈 바구니(리스트)를 만듭니다.
y_list = []  # y 좌표 점들을 모아둘 빈 바구니(리스트)를 만듭니다.

# 💡 y값을 계산해주는 '함수(자판기)'를 만듭니다.
# 원의 방정식 (x^2 + y^2 = 1)을 y에 대해 정리한 식입니다.
def xsqrt(x):
  y = math.sqrt(1 - (x ** 2)) # math.sqrt는 루트(√)를 씌워주는 명령어입니다.
  return y # 계산된 y값을 돌려줍니다.

# 💡 -100부터 100까지 총 201번 반복합니다.
for i in range(-100, 101):
  x = i / 100  # i를 100으로 나누어 x값을 -1.0부터 1.0까지 0.01 간격으로 촘촘하게 만듭니다.
  
  # 하나의 x위치마다 원의 '위쪽 점'과 '아래쪽 점' 2개가 필요하므로 x를 두 번 넣습니다.
  x_list.append(x)  
  x_list.append(x)

  y = xsqrt(x)  # 아까 만든 함수로 위쪽 점의 y좌표(양수)를 계산합니다.
  
  y_list.append(y)   # 위쪽 점(+y)을 바구니에 넣습니다.
  y_list.append(-y)  # 아래쪽 점(-y)을 바구니에 넣습니다.

# 바구니에 잘 담겼는지 화면에 글자로 출력해 봅니다.
print(x_list)
print(y_list)

# 💡 모아둔 x, y 좌표들을 바탕으로 그래프를 그립니다.
plt.scatter(x_list, y_list)  # 1. 점(scatter)만 콕콕 찍어서 보여줍니다. (원의 윤곽선이 됨)

plt.plot(x_list, y_list)     # 2. 찍힌 점들을 순서대로 선(plot)으로 연결합니다. 
                             # (여기서는 위, 아래 점이 번갈아 찍혀서 원 안이 지그재그로 채워지게 됩니다.)
                             
# plt.show()  # (팁: 주피터 노트북이 아닌 일반 파이썬에서는 이 코드를 마지막에 써야 그래프 창이 뜹니다!)

🧑‍🏫 초보자를 위한 전체 흐름 요약 설명

  1. 준비물 챙기기 (import와 리스트)
    그래프를 그리기 위해 matplotlib을, 루트(√) 계산을 위해 math를 가져왔습니다. 그리고 계산된 점들을 담을 x_list와 y_list라는 빈 상자를 준비했습니다.
  2. 계산기 만들기 (def 함수)
    원 위의 점을 찾기 위해 y=1−x2y = \sqrt{1 - x^2} 공식을 계산하는 전용 계산기를 만들었습니다. x를 넣으면 y가 튀어나옵니다.
  3. 촘촘하게 점 찍기 (for 반복문)
    반지름이 1인 원이므로 x는 -1부터 1까지만 존재합니다. 그래서 -1부터 1까지 0.01 간격으로 아주 잘게 쪼개어(i / 100) 계산기에 넣습니다.
    이때 원은 둥글기 때문에 특정 x 위치에서 y값은 항상 위쪽(+y)과 아래쪽(-y) 2개가 생깁니다. 그래서 x_list에는 같은 x를 두 번 넣고, y_list에는 +y와 -y를 각각 넣은 것입니다.
  4. 그림 그리기 (scatter, plot)
    모인 수백 개의 점을 도화지에 던집니다. scatter는 점을 찍어 원의 테두리를 보여주고, plot은 그 점들을 선으로 잇습니다.

이 코드를 실행하시면 콘솔 창에는 수많은 숫자가 출력되고, 그래프 화면에는 파란색 지그재그 선과 점으로 이루어진 멋진 원(Circle) 모양이 나타나게 됩니다!

0개의 댓글