- 목표 : 오락실 pang게임 만들기.
- 캐릭터는 화면 아래에 위치, 좌우로만 이동 가능
- 스페이스를 누르면 무기를 쏘아 올림
- 큰 공 1개가 나타나서 바운스
- 무기에 닿으면 공은 작은 크기 2개로 분할, 가장 작은 크기의 공은 사라짐
- 모든 공을 없애면 게임종료(성공)
- 캐릭터가 공에 닿으면 게임 종료 (실패)
- 시간 제한 99초 초과 시 게임 종료 (실패)
- FPS는 30으로 고정
import pygame
import os
pygame.init()
screen_width = 640
screen_height = 480
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("rusharp Pang")
current_path = os.path.dirname(__file__)
print(current_path)
image_path = os.path.join(current_path,"image")
print(image_path)
weapon_to_remove = -1
ball_to_remove = -1
- os.path.dirname(__file__) : 현재 수행중인 파일 위치를 반환
- os.path.join(a,b) : a\b 를 반환함.
- weapon_to_remove/ball_to_remove : 삭제할 weapons, balls index
backgrouond = pygame.image.load(os.path.join(image_path, "background.png"))
stage = pygame.image.load(os.path.join(image_path,"stage.png"))
stage_size = stage.get_rect().size
stage_height = stage_size[1]
character = pygame.image.load(os.path.join(image_path, "character.png"))
character_rect = character.get_rect()
character_width = character_rect.size[0]
character_height = character_rect.size[1]
character_x =(screen_width - character_width)/ 2
character_y = screen_height - character_height - stage_height
character_speed = 5
to_right = 0
to_left = 0
- character_x/character_y : 캐릭터 초기 위치 및 이동할때마다 rect 저장.
- character_width/character_height : 캐릭 이동 및 무기 위치를 위한 변수.
weapon = pygame.image.load(os.path.join(image_path, "weapon.png"))
weapon_width = weapon.get_rect().size[0]
weapon_height = weapon.get_rect().size[1]
weapons = []
weapon_speed = 10
- weapon_width/weapon_height : 무기 위치 지정을 위한 변수.
- weapons : 스페이스를 누를때마다 무기를 여러번 발사하게끔 list화
# 공 만들기 (크기가 4종류)
ball_image = [pygame.image.load(os.path.join(image_path, "balloon1.png")),
pygame.image.load(os.path.join(image_path, "balloon2.png")),
pygame.image.load(os.path.join(image_path, "balloon3.png")),
pygame.image.load(os.path.join(image_path, "balloon4.png"))]
# 공 크기에 따른 최초 스피드
ball_speed_y = [-18, -15, -12, -9]
# 공 리스트
# 최초 발생하는 큰 공 추가, dictionary 타입
balls = []
balls.append({"pos_x" : 50, #공의 x좌표
"pos_y" : 50, #공의 y좌표
"img_idx" : 0, #공의 이미지 인덱스 (ball_image[n])
"to_x" : 3, #공의 x축 이동방향 (-3 : 좌 / 3 : 우)
"to_y" : -6, # 공의 y축 이동방향
"init_spe_y": ball_speed_y[0]}) # y축의 최초 속도
- ball_image : 공 크기에 맞는 이미지 불러오기
- balls : 공을 생성하기 위한 dictionary list
ㄴ pos_x/pos_y : 공의 x,y좌표
ㄴ to_x / to_y : 공의 x,y축 이동 방향
ㄴ img_idx : 공의 이미지 인덱스, ball_imge의 index 값
ㄴ init_spe_y : 공의 최초 속도, y축 처리함.
clock = pygame.time.Clock()
game_font = pygame.font.Font(None, 40)
total_time = 100
start_ticks = pygame.time.get_ticks()
game_result = "Game Over"
- clock = pygame.time.Clock() : 시간추적개체
- pygame.time.get_ticks() : pygame.init() 호출 후 밀리초를 반환
running = True # 게임이 진행중인가?
while running:
dt = 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:
to_left -=character_speed
elif event.key == pygame.K_RIGHT:
to_right +=character_speed
if event.key == pygame.K_SPACE:
weapon_x = character_x +(character_width-weapon_width)/2
weapon_y = character_y
weapons.append([weapon_x, weapon_y])
elif event.type == pygame.KEYUP:
to_left = 0
to_right = 0
- while running : 게임이 바로 종료되지 않도록 설정함.
- dt = clock.tick(30) : fps를 30으로 설정함.
- event in pygame.event.get() : 입력된 이벤트가 있으면 event에 삽입
- event.type ㄴ pygame.QUIT : 게임 종료(닫기) 버튼
ㄴ pygame.KEYDOWN : 키보드 눌림
ㄴ pygame.KEYUP : 키보드에서 손을 뗌
- event.key
ㄴ pygame.K_RIGHT / LEFT / SPACE : 각각 우, 좌, 스페이스 키
ㄴ to_left 와 to_right 를 나눈 이유는, 캐릭터 이동할 때
방향키를 빠르게 누르면 캐릭터가 아예 멈춰버리는 현상을 방지
- weapons.append([weapon_x, weapon_y]) : space를 누를때마다 무기 추가
character_x =character_x + to_right + to_left
if character_x < 0:
character_x = 0
elif character_x > screen_width-character_width:
character_x = screen_width-character_width
weapons = [ [w[0], w[1] -weapon_speed] for w in weapons]
weapons = [ [w[0], w[1]] for w in weapons if w[1] > 0]
- weapons = [ [w[0], w[1] -weapon_speed] for w in weapons]
ㄴ weapons 의 세로 위치를 점점 줄임으로서 점점 위로 발사되도록 함.
- weapons = [ [w[0], w[1]] for w in weapons if w[1] > 0] : 아래 코드 한줄화
weapons = []
for w in weapons:
if w[1] > 0:
weapons.append = [w[0], w[1]]
for ball_idx, ball_val in enumerate(balls):
ball_pos_x = ball_val["pos_x"]
ball_pos_y = ball_val["pos_y"]
ball_img_idx = ball_val["img_idx"]
ball_size = ball_image[ball_img_idx].get_rect().size
ball_width = ball_size[0]
ball_height = ball_size[1]
if ball_pos_x < 0 or ball_pos_x > screen_width-ball_width:
ball_val["to_x"] *= -1
if ball_pos_y > screen_height-ball_height-stage_height:
ball_val["to_y"] = ball_val["init_spe_y"]
else:
ball_val["to_y"]+=0.5
ball_val["pos_x"] += ball_val["to_x"]
ball_val["pos_y"] += ball_val["to_y"]
- for idx , list in enumerate(LIST): LIST의 번호, 값을 각각 idx, list에 받아옴
- 공 가로가 화면 좌우밖으로 나가는 경우,
공의 x축 이동방향에 -1을 곱한 뒤 x좌표에서 더해 방향을 변경.
- 공 세로가 스테이지 바닥에 닿는 경우, 속도를 초기화함.
- 공의 y축 이동방향에서 0.5 를 더해 음수 > 양수로 만든 뒤
y좌표에 더해 공이 포물선을 이루도록 만듬.
character_rect.x = character_x
character_rect.y = character_y
for ball_idx, ball_val in enumerate(balls):
ball_pos_x = ball_val["pos_x"]
ball_pos_y = ball_val["pos_y"]
ball_rect = ball_image[ball_val["img_idx"]].get_rect()
ball_rect.x = ball_val["pos_x"]
ball_rect.y = ball_val["pos_y"]
ball_img_idx = ball_val["img_idx"]
if ball_rect.colliderect(character_rect):
print("공과 사용자가 충돌하였습니다.")
running = False
break
- 캐릭터와 공의 rect 값에 캐릭터의 현재 x, y 값을 입력함.
- 공.colliderect(캐릭터) 가 True 일 때 게임 종료.
for ball_idx, ball_val in enumerate(balls):
ball_pos_x = ball_val["pos_x"]
ball_pos_y = ball_val["pos_y"]
ball_rect = ball_image[ball_val["img_idx"]].get_rect()
ball_rect.x = ball_val["pos_x"]
ball_rect.y = ball_val["pos_y"]
ball_img_idx = ball_val["img_idx"]
for weapon_idx, weapon_val in enumerate(weapons):
weapon_rect = weapon.get_rect()
weapon_rect.left = weapon_val[0]
weapon_rect.top = weapon_val[1]
if weapon_rect.colliderect(ball_rect):
weapon_to_remove = weapon_idx
ball_to_remove = ball_idx
if ball_img_idx < 3:
ball_width = ball_rect.size[0]
ball_height = ball_rect.size[1]
small_ball_rect = ball_image[ball_img_idx+1].get_rect()
small_ball_width = small_ball_rect.size[0]
small_ball_height = small_ball_rect.size[1]
balls.append({"pos_x" : ball_pos_x + (ball_width - small_ball_width)/2,
"pos_y" : ball_pos_y + (ball_height - small_ball_height)/2,
"img_idx" : ball_img_idx+1,
"to_x" : -3,
"to_y" : -6,
"init_spe_y": ball_speed_y[ball_img_idx+1]})
balls.append({"pos_x" : ball_pos_x + (ball_width - small_ball_width)/2,
"pos_y" : ball_pos_y + (ball_height - small_ball_height)/2,
"img_idx" : ball_img_idx+1,
"to_x" : 3,
"to_y" : -6,
"init_spe_y": ball_speed_y[ball_img_idx+1]})
'''2중 탈출을 하고싶을 때
for문1 :
for문2 :
if 조건 : 액션
break
else: # 조건이 맞지 않으면 continue를 진행하여 for1을 작동함.
continue
break
이렇게하면 break를 만나면 for문1도 break
'''
break
else : continue
break
- weapon 객체 가져옴 → ball 객체 가져옴
ㄴ 만약 weapon과 ball이 충돌하면 삭제할 무기/공 인덱스 저장.
ㄴ if ball_img_idx < 3 : ball이 가장 작은 크기의 공이 아닌지 확인
ㄴ 현재 공의 크기 및 가로/세로 위치를 가져온 뒤 나눠진 공 위치 지정.
ㄴ 왼쪽으로 튕기는 공 / 오른쪽으로 튕기는 공을 각각 추가함.
- for-else : for문이 break 되지 않고 끝까지 실행되면 else문이 작동됨.
즉, 하단 케이스에서 for문2가 break되면 else로 넘어가지 않고 for문1 break됨.
for문1 :
for문2 :
if 조건 : 액션
break
else: # 조건이 맞지 않으면 continue를 진행하여 for1을 작동함.
continue
break
if ball_to_remove > -1:
del balls[ball_to_remove]
ball_to_remove = -1
if weapon_to_remove > -1:
del weapons[weapon_to_remove]
weapon_to_remove = -1
- ball_to_remove / weapon_to_remove = 없애야 할 공, 무기 인덱스
- del list[n] : n번째 리스트 값을 삭제함.
if len(balls) == 0:
game_result = "Mission Complete"
running = False
- del balls[ball_to_remove] 을 통해 공이 더이상 없으면 Mission Complete
elapsed_time = (pygame.time.get_ticks() - start_ticks)/1000
timer = game_font.render("Time : {}".
format(int(total_time - elapsed_time)), True, (0,0,0))
if total_time-elapsed_time <= 0:
game_result = "Time Over"
running = False
- 폰트 객체.render(텍스트,antialias, color) 를 통해 surface 객체로 변환
- 총 시간 - 소요시간이 0보다 작거나 같으면 Time Over
# 화면 출력
screen.blit(backgrouond,(0,0))
for weapon_x, weapon_y in weapons:
screen.blit(weapon, (weapon_x, weapon_y))
for idx, val in enumerate(balls):
ball_x = val["pos_x"]
ball_y = val["pos_y"]
ball_img_idx = val["img_idx"]
screen.blit(ball_image[ball_img_idx], (ball_x, ball_y))
screen.blit(stage, (0, screen_height-stage_height))
screen.blit(character, (character_x, character_y))
screen.blit(timer,(10,10))
pygame.display.update()
- weapons 리스트의 값을 전부 출력
- balls 의 리스트의 모든 값을 출력
- 출력 순서 배경 > 무기 > 공 > stage > 캐릭터 > 타이머
msg = game_font.render(game_result,True, (255,255,0))
msg_rect = msg.get_rect(center = (screen_width/2, screen_height/2))
screen.blit(msg, msg_rect)
pygame.display.update()
pygame.time.delay(2000)
pygame.quit()
- rect 변수 = 객체.get_rect(center = (x,y) ) : 객체의 중앙값을 x, y로 지정한다.
- 게임 종료 메시지를 출력 후 2초 딜레이 후 종료.