티스토리 뷰

pygame_project.zip
0.04MB
pygame_basic.zip
0.01MB

많은 분들이 파이썬 기초까지는 잘 배우지만,

 

 1. 초보를 벗어나 중급자로 실력을 키우려면?
 2. 파이썬을 가지고 뭘 할 수 있는지?

 

이 2가지로 어려움을 겪고 있는 줄로 압니다.

 

그래서 저는 이 분들을 위해서 다양하면서도 쓸모 있는, 총 8개의 실전 프로젝트를 만들며 실력을 키울 수 있는 강의를 제작하기로 하였습니다. 그리고 그 첫번째 프로젝트가 바로 '게임 개발'입니다.

 

이 게임 아시나요?

저도 예전에 오락실에서 종종 했었는데요, 캐릭터가 무기를 쏴서 공을 맞추어 없애는 간단한 게임입니다.

 

파이썬에는 pygame 이라는 유명한 라이브러리가 있구요, 이것을 활용하면 몇 줄 안되는 코드로 손쉽게 게임을 제작할 수 있답니다.
실제로 위 게임을 주석 빼고 약 250 줄의 코드로 만들었어요 ^^

게임에는 이미지 리소스가 반드시 필요한데요, 따로 이미지도 다운로드 받고 편집이라는 번거로운 작업도 거쳐야 해서 관련 프로그램을 잘 다루시는 분들이 아니라면 불편하실 수가 있습니다.

 

그래서 저는 그림판을 통해 쉽게 가짜 이미지를 만들어서 강의를 진행하고 원하시는 분은 나중에 따로 이미지 편집을 통해 입혀보실 수 있도록 준비했습니다.

이런 이미지로 만들어서 작업하니까 시간 낭비도 없어요 ^^

게임 개발 프로젝트는 이런 식으로 진행됩니다.
*개발환경 : VSCode, Python 3.x

 

pygame 기본 사용법을 크게 아래 4단계로 먼저 공부합니다.

 

1. 배경을 하나 만들어 넣어보구요

2. 빨간 게임 캐릭터도 넣어봅니다

3. 이제 캐릭터를 움직여봐야지요?
키보드를 통해 캐릭터를 움직이는 공부를 진행합니다.

4. 노란색 적군(소위 나쁜놈) 을 하나 넣구요,
그리고 충돌 체크를 통해 게임을 종료하는 로직을 넣어봅니다.

기초는 이 정도면 충분합니다.


게임 프레임을 정리하는 시간을 잠깐 가지고 나서 공부하시는 분들이 직접 복습 해보실 수 있게 퀴즈를 하나 드립니다.

퀴즈는 '똥 피하기' 게임이구요, 이런 걸 직접 만들어 봅니다.

우리 강의에서는 똥은 하나씩만 떨어지도록 처리하면 되구요

이렇게 완성하고 나면 게임 이미지를 입혀서 그럴듯하게 만들어봅니다.

퀴즈를 조금 더 응용하면 예전에 한참 유행하던 드래곤 플라이트도 만들어 볼 수 있겠죠?

* 이 부분은 강의에는 포함되지 않습니다.

 

 

마지막으로, 진짜 게임 프로젝트를 진행해봅니다.

1. 배경과 캐릭터를 바로 넣구요

2. 키보드를 통해 좌우로 움직이며 무기도 쏴 봅니다. 원본 게임에서는 무기를 딱 한 발씩만 쏠 수 있는데, 프로젝트에서는 무한대로 쏠 수 있게 합니다. (개발자 마음대로!)

3. 이제 공을 튕겨볼까요?
편의상 공은 네모라고 가정할게요. 바닥에 튕기며 속도 조절도 하고 벽에 닿으면 방향도 바꿉니다.

4. 무기에 닿으면 충돌 감지를 통해 공을 나누어야겠지요

5. 나머지 세세한 부분 구현 및 버그까지 잡고 나서 게임 이미지만 바꿔주면

이렇게 게임이 완성됩니다.

어때요? 원본과 비슷한가요?

 

단 3시간 만에 기초/퀴즈는 물론 프로젝트까지 진행합니다.

비록 pygame 에 대해 모든 것을 다루지는 않지만, 이 정도만 하셔도 취미 삼아 충분히 다양한 게임을 만들 수 있을거라 생각합니다.

 

파이썬을 기초까지는 배우셨는데 한단계 더 나아가고 싶으신 분들, 내 손으로 게임 한 번 만들어 보고 싶으신 분들께 이 강의를 권해 드립니다. ^^

* 강의에서 사용하는 소스코드 및 기본 이미지는 첨부 파일에서 확인할 수 있습니다.

 

 

 

 

잠깐, 질문이 있다면?

지금까지 많은 분들이 가졌던 질문에 대한 답변이 이미 이 곳에 준비 되어 있습니다. ^^ 자주 묻는 질문 게시판을 즐겨찾기에 추가하셨다가 궁금증이 생기면 방문해 보세요 !

 

[파이썬 활용편1] 자주 묻는 질문 (FAQ) 정리

본 게시글에서는 나도코딩 파이썬 활용편1 영상을 학습하시는 분들이 자주 묻는 질문을 정리하였습니다. 영상 순서에 맞도록 구성하였으며 각 질문 마다 태그를 적어두었으니 Ctrl + F 를 통해 찾

nadocoding.tistory.com

 

 

 

 

파이썬을 처음 접하시는 분들은 여기를 클릭해주세요 ^^

 

[나도코딩] 파이썬 기본편 - 소개

이 강의는 파이썬 기본편 강의입니다. 환경설정부터 모듈/패키지까지, 파이썬 사용을 위해 알아야 할 모든 내용을 단기간에 알려드립니다. ▶ 왜 배워야 하나요? Stack Overflow 설문 응답에서 가장

nadocoding.tistory.com

댓글
  • 이전 댓글 더보기
  • 프로필사진 도와주세요.. 무기를 쏴서 큰 공을 쪼개면 그 아래 작은 공 2개가 나오고 그 작은 공을 쏘면 더 작은 공이 안 나오고 프로그램이 종료되요.
    19 공 쪼개기
    #왼쪽으로 튕겨나가는 작은공/#오른쪽으로 튕겨나가는 작은공에서
    "int_spe_y" : ball_speed_y[ball_img_idx + 1] 이 부분을 "int_spe_y" : ball_speed_y[0] 이렇게 쓰면 영상처럼 잘 작동하던데 왜 [ball_img_idx + 1]로 하면 작동이 안될까요..??
    2021.01.31 18:02
  • 프로필사진 호자호식 파이게임을 시작했는데 처음에 검은화면뜨다 취소창을 누르면 이때만 파랑색 벽이랑 빨간공뜨네요 어떡해야하죠?ㅠㅠ 2021.03.16 00:10
  • 프로필사진 고도리 weapons = [[w[0],w[1]] for w in weapons if w[1]>0] 한줄 for 문 말고
    for w in weapons:
    if w[1]>0:
    weapons.append([w[0],w[1]])
    이렇게는 왜 불가능 한가죠?....해결책하고 이유좀 부탁드립니다 들여쓰기 제대로 했습니다..
    2021.03.31 20:38
  • 프로필사진 Juhyunlee_6 실행을 어떻게 하는 지 모르겠어요
    replete.com 에서 파일 두개 추가하고
    그 뒤에 어떻게 하면 되는건가요?
    참고로 맥북입니다!
    2021.04.24 18:11
  • 프로필사진 익명 비밀댓글입니다 2021.05.08 15:30
  • 프로필사진 익명 비밀댓글입니다 2021.05.10 14:30
  • 프로필사진 고난도 성공했습니다.

    생애 처음 만들어 보는 게임이네요
    정말 알기쉽게 설명해주시고, 단계적으로 알려주시니, 따라하다보니 이렇게 뚝딱 게임이 완성되네요.
    게임의 오브젝트 하나하나씩을 다 생각하고 프로그래밍을 한다니 게임 개발자들은 정말 대단한것 같아요.
    앞으로 남은 프로젝트도 열심히 배워 가겠습니다.

    고맙습니다.
    2021.06.10 16:07
  • 프로필사진 썬이 하다가 안되면 해야지 라고 했다가 보니깐 화면에는 적은 코드가 구현이 안됩니다.
    실행하면 밑에 error는 안나는데.
    C:\Users\sarah\PycharmProjects\pythonProject\Pythonpython\venv\Scripts\python.exe
    C:\Users\sarah\PycharmProjects\pythonProject\Pythonpython\1_create_frame.py
    pygame 2.0.1 (SDL 2.0.14, Python 3.9.4)
    Hello from the pygame community. https://www.pygame.org/contribute.html

    Process finished with exit code 0
    이렇게 뜨고 게임은 여전히 맨 처음 검정 화면만 떠요. FPS까지 왔는데 안되네요 ㅠㅠ
    2021.06.11 15:49
  • 프로필사진 홍므파탈 1:00:05 에 보면 game_font.render () 의 안에 함수를 설정하는데,
    render 에 대한 정보가 오른쪽에 막 뜨는데 이건 어떻게 설정해야 뜨는건가요?
    2021.06.24 15:43
  • 프로필사진 파린이 나도코딩님 안녕하세요. 다름이 아니라 강의 내용에 포함 안 되어 있는 드래곤 플라이트 게임을 만들어보았는데요, 무기를 이용해 내려오는 적을 공격해 없애고 나머지 적들이 바닥에 닿았을 때 없어진 적을 포함한 새로운 적들이 다시 내려오게 하려면 어떻게 해야 할까요.. 2021.07.17 12:12
  • 프로필사진 코딩꾸러기 캐릭터가 안움직여요
    에러 메세지도 없고요
    사진으로 보여드릴게요
    file:///C:/Users/user/Desktop/%EC%83%88%20%ED%85%8D%EC%8A%A4%ED%8A%B8%20%EB%AC%B8%EC%84%9C.html
    2021.08.04 13:43
  • 프로필사진 주주파파 완성된 게임의 이미지 소스는 없나요?
    파일로 부탁드립니다.
    2021.09.11 15:41
  • 프로필사진 break 유튜브 보고 간단한 게임을 만들어보고 있는데요, 왠만하면 스스로 해결해보려고 했지만 아무리 생각해봐도 모르겠네요.

    https://www.youtube.com/watch?v=Dkx8Pl6QKW0
    이 영상 중간 ~ 후반부에서 나오는 게임을 코딩하고 있는데, 어렸을 적 오락실에서 했던 아래 캐릭터가 줄 같은 걸 위로 쏴 공을 맞추면 큰 공이 작은 두 공으로 갈라지고, 이를 반복해 더이상 공이 갈라지지 않고 사라질 때까지 하는 게임을 만들고 있습니다.

    다른 경우 다 잘 작동하나 한 자리에서 스페이스바를 매우 빠르게 눌러 줄을 위로 여러 겹 겹치게 쐈을 때 공이 좌우로 튀다가 줄의 옆 부분에 닿으면 아래 에러 메시지가 뜹니다.

    아래 에러 메시지가 뜹니다.
    *예외가 발생했습니다. ValueError*

    {‘x_pos’: 216, ‘y_pos’: 86.0, ‘to_x’: 6, ‘to_y’: -12.0, ‘idx’: 0} is not in list
    File “_/Users/haseunghyeon/Desktop/PhytonWorkspace/pygame.project/balls_game.py_”, line 224, in <module>
    * del balls[balls.index(b)]

    공이 줄의 어느 부분에 닿든 충돌 이벤트가 발생했을 때 두 개의 작은 공으로 갈라져야 하는데 위의 에러 메시지가 뜨고 종료됩니다. 이상하게도 공의 아래쪽에서 매우 빠르게 줄을 겹쳐서 쏜다면 위의 에러 메시지가 안 뜨는데 옆에서 오는 공을 줄을 연타로 겹쳐 대기하고 있으면 공이 와서 충돌하고 위의 에러가 발생합니다. 아마도 중복과 관련된 것 같습니다. 공의 아래에서 빠르게 스페이스바를 눌러 공을 맞추는 경우는 아무리 빨라도 간격이 있을 수밖에 없기에 순차적으로 진행할 수 있습니다. 그러나 다량의 줄을 겹쳐 이미 발사해놓고 대기하고 있는 경우라면 공이 줄 옆으로 와 부딪칠 때 하나의 공은 여러 겹의 줄과 충돌하게 됩니다. 제 생각에는 이 부분과 관련이 있는 것 같은데 정확히 왜 그런 건지 잘 모르겠네요. 우선 아래 코드입니다. 점섬 표시된 부분이 공과 반복문 구간이고 안쪽 무기 반복문 가장 아래 공을 삭제하는 부분에서 오류가 납니다.

    import os
    import pygame
    import random

    pygame.init()

    # 스크린 크기
    screen_width = 640
    screen_height = 480

    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("공 부수기")

    # 이미지 경로
    current_path = os.path.dirname(__file__)
    imgaes_path = os.path.join(current_path, "images")

    background = pygame.image.load(os.path.join(imgaes_path, "background.png"))

    stage = pygame.image.load(os.path.join(imgaes_path, "stage.png"))
    stage_height = stage.get_rect().size[1]

    # 캐릭터 정의
    character = pygame.image.load(os.path.join(imgaes_path, "character.png"))
    character_width = character.get_rect().size[0]
    character_height = character.get_rect().size[1]
    character_x_pos = screen_width /2 - character_width /2
    character_y_pos = screen_height - stage_height - character_height
    character_to_x_left= 0
    character_to_x_right= 0
    character_speed = 10

    # 공 이미지
    ball_images = [pygame.image.load(os.path.join(imgaes_path, "balloon1.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon2.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon3.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon4.png"))
    ]

    # 줄 이미지 및 변수
    weapon = pygame.image.load(os.path.join(imgaes_path, "weapon.png"))
    weapon_width = weapon.get_rect().size[0]
    weapon_speed = -10

    # 줄이 천장에 닿기 전까지의 줄
    weapons = []
    # 줄이 천장에 닿을 때 멈춰있을 시간 변수
    weapons_time = []
    # 줄이 천장에 닿을 때 멈춰있는 줄
    weapons_delay = []

    # 공의 좌우, 상하 속도
    ball_y_speeds = [-18, -16, -14, -12]
    ball_x_speeds = [6, 5, 4, 3]

    # 공 추가
    ball_max = range(2)
    balls = []
    for ball in ball_max:
    ball = {
    "x_pos" : random.randint(0, screen_width - ball_images[0].get_rect().size[0]),
    "y_pos" : 50,
    "to_x" : ball_x_speeds[0],
    "to_y" : -6,
    "idx" : 0}
    balls.append(ball)

    game_font = pygame.font.Font(None, 40)
    clock = pygame.time.Clock()
    score = 0
    msg = "Mission Complete"

    total_time = 60
    start_ticks = pygame.time.get_ticks()

    running = True
    while running:
    clock.tick(30)
    # 키 이벤트 처리, 캐릭터 좌우 이동 및 줄 발사
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    running = False
    if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
    character_to_x_left = character_speed
    elif event.key == pygame.K_RIGHT:
    character_to_x_right = character_speed
    elif event.key == pygame.K_SPACE:
    # weapon = {"x_pos" : character_x_pos + character_width/2 - weapon_width/2,
    # "y_pos" : character_y_pos}
    # weapons.append(weapon)

    weapon_x_pos = character_x_pos + character_width/2 - weapon_width/2
    weapon_y_pos = character_y_pos
    weapons.append([weapon_x_pos, weapon_y_pos])

    elif event.type == pygame.KEYUP:
    if event.key == pygame.K_LEFT:
    character_to_x_left = 0
    elif event.key == pygame.K_RIGHT:
    character_to_x_right = 0

    # 캐릭터 좌우 이동 좌표값과 이동할 수 있는 경계값 처리
    character_x_pos = character_x_pos - character_to_x_left + character_to_x_right
    if character_x_pos < 0:
    character_x_pos = 0
    elif character_x_pos > screen_width - character_width:
    character_x_pos = screen_width - character_width

    # 추가된 공들의 이동
    for b in balls:
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]
    b_idx = b["idx"]

    ball_size = ball_images[b_idx].get_rect().size
    ball_width = ball_size[0]
    ball_height = ball_size[1]

    if b_x_pos >= screen_width - ball_width or b_x_pos <= 0:
    b["to_x"] *= -1

    if b_y_pos >= screen_height - stage_height - ball_height:
    b["to_y"] = ball_y_speeds[b_idx]
    else:
    b["to_y"] += 0.5

    b["x_pos"] += b["to_x"]
    b["y_pos"] += b["to_y"]

    # 발사된 줄의 이동과 경계값, 줄이 천장에 닿았을 때 weapons_delay에 추가하고 기존의 weapons에 제거
    for w in weapons:
    w[1] += weapon_speed
    if w[1] <= 0:
    w[1] = 0
    weapons_delay.append([w[0], w[1]])
    weapons_time.append(pygame.time.get_ticks())
    del weapons[weapons.index([w[0], w[1]])]

    # 0.5초 후에 천장에 닿은 줄과 해당되는 시간 제거
    for w in weapons_delay:
    if (pygame.time.get_ticks() - weapons_time[weapons_delay.index([w[0], w[1]])])/1000 >= 0.5:
    del weapons_time[weapons_delay.index([w[0], w[1]])]
    del weapons_delay[weapons_delay.index([w[0], w[1]])]

    character_rect = character.get_rect()
    character_rect.left = character_x_pos
    character_rect.top = character_y_pos

    # 공과 캐릭터 충돌 처리
    for b in balls:
    b_idx = b["idx"]
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]

    b_rect = ball_images[b_idx].get_rect()
    b_rect.left = b_x_pos
    b_rect.top = b_y_pos

    if character_rect.colliderect(b_rect):
    running = False
    msg = "Character_Killed"
    break
    -------- -------- -------- -------- -------- -------- -------- --------
    # 공과 줄(무기)의 충돌 처리
    for w in weapons:
    w_rect = weapon.get_rect()
    w_rect.left = w[0]
    w_rect.top = w[1]

    if w_rect.colliderect(b_rect):
    if b_idx < 3:
    small_b_rect = ball_images[b_idx+1].get_rect()
    small_b_width = small_b_rect.size[0]
    small_b_height = small_b_rect.size[1]

    b_width = b_rect.size[0]
    b_height = b_rect.size[1]

    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })
    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : - ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })

    score += (20 + ball_y_speeds[b_idx]) * 10

    del weapons[weapons.index([w[0], w[1]])]
    del balls[balls.index(b)] # 오류 부분
    break
    # else:
    # continue
    # break

    for wd in weapons_delay:
    wd_rect = weapon.get_rect()
    wd_rect.left = wd[0]
    wd_rect.top = wd[1]

    if wd_rect.colliderect(b_rect):
    if b_idx < 3:
    small_b_rect = ball_images[b_idx+1].get_rect()
    small_b_width = small_b_rect.size[0]
    small_b_height = small_b_rect.size[1]

    b_width = b_rect.size[0]
    b_height = b_rect.size[1]

    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })
    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : - ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })

    score += (20 + ball_y_speeds[b_idx]) * 10
    del weapons_delay[weapons_delay.index([wd[0], wd[1]])]
    del balls[balls.index(b)] #오류 부분
    break
    # else:
    # continue
    # break
    -------- -------- -------- -------- -------- -------- -------- --------

    elapsed_time = (pygame.time.get_ticks() - start_ticks) / 1000
    if total_time - elapsed_time <= 0:
    msg = "Time Over"
    running = False

    if len(balls) == 0:
    msg = "Zero Ball, Complete"
    running = False

    screen.blit(background, (0, 0))

    for w in weapons:
    screen.blit(weapon, (w[0], w[1]))
    for w in weapons_delay:
    screen.blit(weapon, (w[0], w[1]))

    for b in balls:
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]
    b_idx = b["idx"]

    screen.blit(ball_images[b_idx], (b_x_pos, b_y_pos))

    screen.blit(stage, (0, screen_height - stage_height))
    screen.blit(character, (character_x_pos, character_y_pos))

    timer = game_font.render(str(int(total_time - elapsed_time)), True, (255, 255, 255))
    screen.blit(timer, (10, 10))

    scorer = game_font.render(str(score), True, (255, 255, 255))
    screen.blit(scorer, (screen_width - 100, 10))
    pygame.display.update()

    msger = game_font.render("{0} + {1}" .format(msg, score), True, (255, 255, 0))
    msger_rect = msger.get_rect(center = (screen_width/2, screen_height/2))
    screen.blit(msger, (msger_rect))

    pygame.display.update()
    pygame.time.delay(2000)
    pygame.quit()
    --------------------------------------------------------------------------------------------------------------------
    주석처리 한 이중 반복문 탈출문 else:, continue, break, 부분을 코드처리를 하면 이상 없이 잘 작동합니다. 이 지점이 이해가 안 되네요. 공 하나에 무기 리스트를 점검하고 다음 공 하나의 무기 리스트를 점검하는 이중 반복문으로 되어 있는데, 줄을 여러 겹 중첩했더라도 공이 옆에 와 부딪치면 충돌 조건문이 실행되고, 거기서 break를 하여 안쪽 무기 반복문을 탈출합니다. 그리고 그 다음 공을 확인하는 반복문으로 진입하는데 그렇게 되면, 중복 충돌이 발생하더라도 반복문이 탈출되어 다음으로 넘어갑니다. 아무리 생각해도 이상이 없어 보이는데, 해당되는 공의 값이 없다는 오류가 나옵니다. 왜 이런 건가요? 그리고 왜 이중 반복문을 탈출하면 이런 문제가 해결되나요?
    2021.09.16 18:40
  • 프로필사진 break 유튜브 보고 간단한 게임을 만들어보고 있는데요, 왠만하면 스스로 해결해보려고 했지만 아무리 생각해봐도 모르겠네요.

    https://www.youtube.com/watch?v=Dkx8Pl6QKW0
    이 영상 중간 ~ 후반부에서 나오는 게임을 코딩하고 있는데, 어렸을 적 오락실에서 했던 아래 캐릭터가 줄 같은 걸 위로 쏴 공을 맞추면 큰 공이 작은 두 공으로 갈라지고, 이를 반복해 더이상 공이 갈라지지 않고 사라질 때까지 하는 게임을 만들고 있습니다.

    다른 경우 다 잘 작동하나 한 자리에서 스페이스바를 매우 빠르게 눌러 줄을 위로 여러 겹 겹치게 쐈을 때 공이 좌우로 튀다가 줄의 옆 부분에 닿으면 아래 에러 메시지가 뜹니다.

    아래 에러 메시지가 뜹니다.
    *예외가 발생했습니다. ValueError*

    {‘x_pos’: 216, ‘y_pos’: 86.0, ‘to_x’: 6, ‘to_y’: -12.0, ‘idx’: 0} is not in list
    File “_/Users/haseunghyeon/Desktop/PhytonWorkspace/pygame.project/balls_game.py_”, line 224, in <module>
    * del balls[balls.index(b)]

    공이 줄의 어느 부분에 닿든 충돌 이벤트가 발생했을 때 두 개의 작은 공으로 갈라져야 하는데 위의 에러 메시지가 뜨고 종료됩니다. 이상하게도 공의 아래쪽에서 매우 빠르게 줄을 겹쳐서 쏜다면 위의 에러 메시지가 안 뜨는데 옆에서 오는 공을 줄을 연타로 겹쳐 대기하고 있으면 공이 와서 충돌하고 위의 에러가 발생합니다. 아마도 중복과 관련된 것 같습니다. 공의 아래에서 빠르게 스페이스바를 눌러 공을 맞추는 경우는 아무리 빨라도 간격이 있을 수밖에 없기에 순차적으로 진행할 수 있습니다. 그러나 다량의 줄을 겹쳐 이미 발사해놓고 대기하고 있는 경우라면 공이 줄 옆으로 와 부딪칠 때 하나의 공은 여러 겹의 줄과 충돌하게 됩니다. 제 생각에는 이 부분과 관련이 있는 것 같은데 정확히 왜 그런 건지 잘 모르겠네요. 우선 아래 코드입니다. 점섬 표시된 부분이 공과 반복문 구간이고 안쪽 무기 반복문 가장 아래 공을 삭제하는 부분에서 오류가 납니다.

    import os
    import pygame
    import random

    pygame.init()

    # 스크린 크기
    screen_width = 640
    screen_height = 480

    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("공 부수기")

    # 이미지 경로
    current_path = os.path.dirname(__file__)
    imgaes_path = os.path.join(current_path, "images")

    background = pygame.image.load(os.path.join(imgaes_path, "background.png"))

    stage = pygame.image.load(os.path.join(imgaes_path, "stage.png"))
    stage_height = stage.get_rect().size[1]

    # 캐릭터 정의
    character = pygame.image.load(os.path.join(imgaes_path, "character.png"))
    character_width = character.get_rect().size[0]
    character_height = character.get_rect().size[1]
    character_x_pos = screen_width /2 - character_width /2
    character_y_pos = screen_height - stage_height - character_height
    character_to_x_left= 0
    character_to_x_right= 0
    character_speed = 10

    # 공 이미지
    ball_images = [pygame.image.load(os.path.join(imgaes_path, "balloon1.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon2.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon3.png")),
    pygame.image.load(os.path.join(imgaes_path, "balloon4.png"))
    ]

    # 줄 이미지 및 변수
    weapon = pygame.image.load(os.path.join(imgaes_path, "weapon.png"))
    weapon_width = weapon.get_rect().size[0]
    weapon_speed = -10

    # 줄이 천장에 닿기 전까지의 줄
    weapons = []
    # 줄이 천장에 닿을 때 멈춰있을 시간 변수
    weapons_time = []
    # 줄이 천장에 닿을 때 멈춰있는 줄
    weapons_delay = []

    # 공의 좌우, 상하 속도
    ball_y_speeds = [-18, -16, -14, -12]
    ball_x_speeds = [6, 5, 4, 3]

    # 공 추가
    ball_max = range(2)
    balls = []
    for ball in ball_max:
    ball = {
    "x_pos" : random.randint(0, screen_width - ball_images[0].get_rect().size[0]),
    "y_pos" : 50,
    "to_x" : ball_x_speeds[0],
    "to_y" : -6,
    "idx" : 0}
    balls.append(ball)

    game_font = pygame.font.Font(None, 40)
    clock = pygame.time.Clock()
    score = 0
    msg = "Mission Complete"

    total_time = 60
    start_ticks = pygame.time.get_ticks()

    running = True
    while running:
    clock.tick(30)
    # 키 이벤트 처리, 캐릭터 좌우 이동 및 줄 발사
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    running = False
    if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
    character_to_x_left = character_speed
    elif event.key == pygame.K_RIGHT:
    character_to_x_right = character_speed
    elif event.key == pygame.K_SPACE:
    # weapon = {"x_pos" : character_x_pos + character_width/2 - weapon_width/2,
    # "y_pos" : character_y_pos}
    # weapons.append(weapon)

    weapon_x_pos = character_x_pos + character_width/2 - weapon_width/2
    weapon_y_pos = character_y_pos
    weapons.append([weapon_x_pos, weapon_y_pos])

    elif event.type == pygame.KEYUP:
    if event.key == pygame.K_LEFT:
    character_to_x_left = 0
    elif event.key == pygame.K_RIGHT:
    character_to_x_right = 0

    # 캐릭터 좌우 이동 좌표값과 이동할 수 있는 경계값 처리
    character_x_pos = character_x_pos - character_to_x_left + character_to_x_right
    if character_x_pos < 0:
    character_x_pos = 0
    elif character_x_pos > screen_width - character_width:
    character_x_pos = screen_width - character_width

    # 추가된 공들의 이동
    for b in balls:
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]
    b_idx = b["idx"]

    ball_size = ball_images[b_idx].get_rect().size
    ball_width = ball_size[0]
    ball_height = ball_size[1]

    if b_x_pos >= screen_width - ball_width or b_x_pos <= 0:
    b["to_x"] *= -1

    if b_y_pos >= screen_height - stage_height - ball_height:
    b["to_y"] = ball_y_speeds[b_idx]
    else:
    b["to_y"] += 0.5

    b["x_pos"] += b["to_x"]
    b["y_pos"] += b["to_y"]

    # 발사된 줄의 이동과 경계값, 줄이 천장에 닿았을 때 weapons_delay에 추가하고 기존의 weapons에 제거
    for w in weapons:
    w[1] += weapon_speed
    if w[1] <= 0:
    w[1] = 0
    weapons_delay.append([w[0], w[1]])
    weapons_time.append(pygame.time.get_ticks())
    del weapons[weapons.index([w[0], w[1]])]

    # 0.5초 후에 천장에 닿은 줄과 해당되는 시간 제거
    for w in weapons_delay:
    if (pygame.time.get_ticks() - weapons_time[weapons_delay.index([w[0], w[1]])])/1000 >= 0.5:
    del weapons_time[weapons_delay.index([w[0], w[1]])]
    del weapons_delay[weapons_delay.index([w[0], w[1]])]

    character_rect = character.get_rect()
    character_rect.left = character_x_pos
    character_rect.top = character_y_pos

    # 공과 캐릭터 충돌 처리
    for b in balls:
    b_idx = b["idx"]
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]

    b_rect = ball_images[b_idx].get_rect()
    b_rect.left = b_x_pos
    b_rect.top = b_y_pos

    if character_rect.colliderect(b_rect):
    running = False
    msg = "Character_Killed"
    break
    -------- -------- -------- -------- -------- -------- -------- --------
    # 공과 줄(무기)의 충돌 처리
    for w in weapons:
    w_rect = weapon.get_rect()
    w_rect.left = w[0]
    w_rect.top = w[1]

    if w_rect.colliderect(b_rect):
    if b_idx < 3:
    small_b_rect = ball_images[b_idx+1].get_rect()
    small_b_width = small_b_rect.size[0]
    small_b_height = small_b_rect.size[1]

    b_width = b_rect.size[0]
    b_height = b_rect.size[1]

    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })
    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : - ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })

    score += (20 + ball_y_speeds[b_idx]) * 10

    del weapons[weapons.index([w[0], w[1]])]
    del balls[balls.index(b)] # 오류 부분
    break
    # else:
    # continue
    # break

    for wd in weapons_delay:
    wd_rect = weapon.get_rect()
    wd_rect.left = wd[0]
    wd_rect.top = wd[1]

    if wd_rect.colliderect(b_rect):
    if b_idx < 3:
    small_b_rect = ball_images[b_idx+1].get_rect()
    small_b_width = small_b_rect.size[0]
    small_b_height = small_b_rect.size[1]

    b_width = b_rect.size[0]
    b_height = b_rect.size[1]

    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })
    balls.append({
    "x_pos" : b_x_pos + b_width/2 - small_b_width/2,
    "y_pos" : b_y_pos + b_height/2 - small_b_height/2,
    "to_x" : - ball_x_speeds[b_idx + 1],
    "to_y" : -6,
    "idx" : b_idx + 1
    })

    score += (20 + ball_y_speeds[b_idx]) * 10
    del weapons_delay[weapons_delay.index([wd[0], wd[1]])]
    del balls[balls.index(b)] #오류 부분
    break
    # else:
    # continue
    # break
    -------- -------- -------- -------- -------- -------- -------- --------

    elapsed_time = (pygame.time.get_ticks() - start_ticks) / 1000
    if total_time - elapsed_time <= 0:
    msg = "Time Over"
    running = False

    if len(balls) == 0:
    msg = "Zero Ball, Complete"
    running = False

    screen.blit(background, (0, 0))

    for w in weapons:
    screen.blit(weapon, (w[0], w[1]))
    for w in weapons_delay:
    screen.blit(weapon, (w[0], w[1]))

    for b in balls:
    b_x_pos = b["x_pos"]
    b_y_pos = b["y_pos"]
    b_idx = b["idx"]

    screen.blit(ball_images[b_idx], (b_x_pos, b_y_pos))

    screen.blit(stage, (0, screen_height - stage_height))
    screen.blit(character, (character_x_pos, character_y_pos))

    timer = game_font.render(str(int(total_time - elapsed_time)), True, (255, 255, 255))
    screen.blit(timer, (10, 10))

    scorer = game_font.render(str(score), True, (255, 255, 255))
    screen.blit(scorer, (screen_width - 100, 10))
    pygame.display.update()

    msger = game_font.render("{0} + {1}" .format(msg, score), True, (255, 255, 0))
    msger_rect = msger.get_rect(center = (screen_width/2, screen_height/2))
    screen.blit(msger, (msger_rect))

    pygame.display.update()
    pygame.time.delay(2000)
    pygame.quit()
    --------------------------------------------------------------------------------------------------------------------
    주석처리 한 이중 반복문 탈출문 else:, continue, break, 부분을 코드처리를 하면 이상 없이 잘 작동합니다. 이 지점이 이해가 안 되네요. 공 하나에 무기 리스트를 점검하고 다음 공 하나의 무기 리스트를 점검하는 이중 반복문으로 되어 있는데, 줄을 여러 겹 중첩했더라도 공이 옆에 와 부딪치면 충돌 조건문이 실행되고, 거기서 break를 하여 안쪽 무기 반복문을 탈출합니다. 그리고 그 다음 공을 확인하는 반복문으로 진입하는데 그렇게 되면, 중복 충돌이 발생하더라도 반복문이 탈출되어 다음으로 넘어갑니다. 아무리 생각해도 이상이 없어 보이는데, 해당되는 공의 값이 없다는 오류가 나옵니다. 왜 이런 건가요? 그리고 왜 이중 반복문을 탈출하면 이런 문제가 해결되나요?
    2021.09.16 18:40
  • 프로필사진 bms 정말 좋은 강의 감사합니다!!

    지금 따라서 해보고 있는데 캐릭터가 창 밖으로 안 나가게 하려고 경계값 설정한 부분에서 아무리 봐도 똑같이 했는데 위와 왼쪽은 안 나가는데 오른쪽과 아래로 캐릭터가 나가는데 문제가 뭔지 모르겠어요ㅜㅜ

    혹시 한번 봐주실수있나요?

    import pygame

    pygame.init() # 초기화 (반드시 필요)

    # 화면 크기 설정
    screen_width = 1200 # 가로 크기
    screen_height = 700 # 세로 크기
    screen = pygame.display.set_mode((screen_width, screen_height))

    # 화면 타이틀 설정
    pygame.display.set_caption("Nado Game") # 게임 이름

    # FPS
    clock = pygame.time.Clock()

    # 배경 이미지 불러오기
    background = pygame.image.load("C:/Users/minsu/Documents/PythonWorkspace/pygame_basic/background.png")

    # 캐릭터(스프라이트) 불러오기
    character = pygame.image.load("C:/Users/minsu/Documents/PythonWorkspace/pygame_basic/character.png")
    character_size = character.get_rect().size # 이미지의 크기를 구해옴
    character_width = character_size[0] # 캐릭터의 가로 크기
    character_height = character_size[1] # 캐릭터의 세로 크기
    character_x_pos = (screen_width - character_width) / 2 # 가로 위치
    character_y_pos = screen_height - character_height # 세로 위치

    # 이동할 좌표
    to_x = 0
    to_y = 0

    # 이동 속도
    character_speed = 1

    # 이벤트 루프
    running = True # 게임이 진행중인가?
    while running:
    dt = clock.tick(60) # 게임화면의 초당 프레임 수를 설정
    # moving 100 in 1 second under 10 fps (10 per sec) -> need to move 10 per movement = 10 * 10번
    # moving 100 in 1 second under 20 fps (20 per sec) -> need to move 5 per movement = 5 * 20번

    for event in pygame.event.get(): # 어떤 이벤트가 발생하였는가?
    if event.type == pygame.QUIT: # 창이 닫히는 이벤트가 발생하였는가?
    running = False # 게임이 진행중이 아님

    if event.type == pygame.KEYDOWN: # 키가 눌러졌는지 확인
    if event.key == pygame.K_LEFT: # 캐릭터를 왼쪽으로
    to_x -= character_speed # to_x = to_x - 5
    elif event.key == pygame.K_RIGHT: # 캐릭터를 오른쪽으로
    to_x += character_speed
    elif event.key == pygame.K_UP: # 캐릭터를 위로
    to_y -= character_speed
    elif event.key == pygame.K_DOWN: # 캐릭터를 아래로
    to_y += character_speed

    if event.type == pygame.KEYUP: # 방향키를 때면 멈춤
    if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
    to_x = 0
    elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
    to_y = 0

    character_x_pos += to_x * dt
    character_y_pos += to_y * dt

    # 가로 경계값 처리
    if character_x_pos < 0:
    character_x_pos = 0
    elif character_x_pos > screen_width - character_width:
    charactor_x_pos = screen_width - character_width

    # 세로 경계값 처리
    if character_y_pos < 0:
    character_y_pos = 0
    elif character_y_pos > screen_height - character_height:
    charactor_y_pos = screen_height - character_height

    # screen.fill((0, 200, 255)) <- (optional) 이미지 불러오지 않고 RGB로 배경설정하는 방법
    screen.blit(background, (0, 0)) # 배경 그리기 및 위치 설정
    screen.blit(character, (character_x_pos, character_y_pos)) # 캐릭터 그리기 및 위치 설정

    pygame.display.update()

    # pygame 종료
    pygame.quit()
    2021.10.20 11:58
  • 프로필사진 $_$ 각 경계값 처리에서 elif 부분에 character_y_pos를 charactor_y_pos로 적으셨네요. 2021.11.12 16:52
  • 프로필사진 김용우 안녕하세요 닥븐에 파이선에 재미를 붙이고 있습니다 ^^
    활용편(게임제작) 동영상을 보다가 실숩증에요
    배경이미지와 볼이미지를 변경 해봤습니다
    그런데 배경이미지에 볼이미지가 그려질때 볼이미지 사각형이 그대로 나오더라구요
    이거 어떻게 해결해야 하나요?
    감사합니다
    2021.12.23 08:28
  • 프로필사진 배게 잘 보고 갑니다
    2022.02.08 15:56 신고
  • 프로필사진 양경일 귀중한 강의 감사합니다. 2022.03.26 20:12
  • 프로필사진 PASS 키보드 이벤트 부분에서 질문 있습니다.
    이거 반응성을 좀 빠르게 하고 싶어요. 이거 게임 완성하신 분들 어떤 상태신가요?
    이게 위 오른쪽 아래 왼쪽 이런 순서로 방향키를 누르면 방향전환이 잘 되는데
    왼쪽 방향키 눌렀다가 오른쪽 방향키를 누르거나 위 방향키를 눌렀다가 아래 방향키를 누르면 전환이 잘 안되는 것 같아요.
    이 강의를 아직 끝까지 듣지 않은 상태고 이 지점에서 이걸 어떻게 개선할 수 있을지 고민 중인데
    혹시 반응성 해결하신 분들 계실까요.
    2022.04.12 00:59
  • 프로필사진 PASS 이거 해결했는데
    pygame.key.getpressed()
    를 활용을 잘 하면 되네요.

    하나 의문이 드는건 기존의 강의 내용대로 하는 경우 급격한 방향전환을 할 때
    키 자체는 인식을 하는 것 같은데 움직이지는 않네요. (print문으로 찍어보니 키를 인식한 상황 자체는 알 수 있는 것 같아요.)

    이거 그런데 하다보니까 ㅋㅋ
    기존코드에서 KEYUP 조건문에서 정지가 실행될때 이게 급격한 방향전환을 읽어내지 못하내요!

    논리적으로는 코드는 분명 맞는데
    신기하네요 ㅋㅋㅋㅋㅋㅋ
    오늘 공부 많이 하고 가네요
    디버깅을 하는데 순간적인 방향전환시
    if 정지문이 눌리지 않은 것으로 인식을 한다. 이게 근본적인 이유였네요.

    아 근데 왜 이런지 좀 궁금하네요.
    뭔가 이유가 있을 것 같은데..
    왜 이런 반응성 문제가 나오는 것인지
    2022.04.13 00:09
  • 프로필사진 코딩조아 강의를 너무 잘 보았습니다.

    그런데 마지막에 보여주신 image 파일은 어디에서 구할 수가 있나요???
    2022.05.17 16:39
댓글쓰기 폼
공지사항
Total
953,455
Today
682
Yesterday
1,482
링크
«   2022/07   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
글 보관함