import pygame
import sys
import math
import random
from pygame.locals import *
# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/galaxy.png')
img_sship = [
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_l.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_r.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_burner.png')
]
img_weapon = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/bullet.png')
img_shield = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/shield.png')
img_enemy = [
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/enemy0.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/enemy1.png')
]
img_explode = [
None,
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion1.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion2.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion3.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion4.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion5.png')
]
tmr = 0
bg_y = 0
ss_x = 480 # 플레이어 기체의 X 좌표
ss_y = 360 # 플레이어 기체의 Y 좌표
ss_d = 0 # 플레이어 기체의 기울기 변수
ss_shield = 100 # 플레이어 기체의 실드량 변수
ss_muteki = 0 # 플레이어 기체의 무적 상태 변수
key_spc = 0 # 스페이스 키를 눌렀을 때 사용하는 변수
key_z = 0 # Z 키를 눌렀을 때 사용할 변수
MISSILE_MAX = 200 # 플레이어가 발사한 최대 탄환 수 정의
msl_no = 0 # 탄환 발사에 사용할 리스트 인덱스 변수
msl_f = [False] * MISSILE_MAX # 탄환을 발사 중인지 관리하는 플래그 리스트
msl_x = [0] * MISSILE_MAX # 탄환의 X, Y 좌표 리스트
msl_y = [0] * MISSILE_MAX
msl_a = [0] * MISSILE_MAX # 탄환이 날아가는 각도 리스트
ENEMY_MAX = 100 # 적 최대 수 정의
emy_no = 0 # 적 등장시 사용할 리스트 인덱스 변수
emy_f = [False] * ENEMY_MAX # 적 등장 여부 관리 플래그 리스트
emy_x = [0] * ENEMY_MAX # 적 X, Y 좌표 리스트
emy_y = [0] * ENEMY_MAX
emy_a = [0] * ENEMY_MAX # 적의 비행 각도 리스트
emy_type = [0] * ENEMY_MAX # 적의 종류 리스트
emy_speed = [0] * ENEMY_MAX # 적 속도 리스트
EMY_BULLET = 0 # 적의 탄환 번호 관리 상수
LINE_T = -80 # 적이 나타나는(사라지는) 위쪽 좌표
LINE_B = 800 # 적이 나타나는(사라지는) 아래쪽 좌표
LINE_L = -80 # 적이 나타나는(사라지는) 왼쪽 좌표
LINE_R = 1040 # 적이 나타나는(사라지는) 오른쪽 좌표
EFFECT_MAX = 100 # 폭발 연출 최대 수 정의
eff_no = 0 # 폭발 연출 시 사용할 리스트 인덱스 변수
eff_p = [0] * EFFECT_MAX # 폭발 연출 이미지 번호 리스트
eff_x = [0] * EFFECT_MAX # 폭발 연출 X, Y 좌표 리스트
eff_y = [0] * EFFECT_MAX
def get_dis(x1, y1, x2, y2): # 두 점 사이 거리 계산
return ((x1 -x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
def move_starship(scrn, key): # 플레이어 기체 이동
global ss_x, ss_y, ss_d, ss_shield, ss_muteki, key_spc, key_z
ss_d = 0 # 기체 기울기 변수에 0(기울지 않음 대입)
if key[K_UP] == 1: # 방향 키를 눌렀다면
ss_y = ss_y - 20
if ss_y < 80: # 화면 밖으로 나가지 않도록 조정
ss_y = 80
if key[K_DOWN] == 1:
ss_y = ss_y + 20
if ss_y > 640:
ss_y = 640
if key[K_LEFT] == 1:
ss_d = 1 # 기체 기울기 변수에 1(왼쪽) 대입
ss_x = ss_x - 20
if ss_x < 40:
ss_x = 40
if key[K_RIGHT] == 1:
ss_d = 2 # 기체 기울기 변수에 2(오른쪽) 대입
ss_x = ss_x + 20
if ss_x > 920:
ss_x = 920
key_spc = (key_spc + 1) * key[K_SPACE] # 스페이스 키를 누르는 동안 변수 값 증가
if key_spc % 5 == 1: # 스페이스 키를 처음 누른 후, 5 프레임마다
set_missile(0) # 탄환 발사
key_z = (key_z + 1) * key[K_z] # Z 키를 누르는 동안 변수 값 증가
if key_z == 1 and ss_shield > 10: # 1 번 눌렀을 때 실드량이 10보다 크다면
set_missile(10) # 탄막 치기
ss_shield = ss_shield - 10 # 실드량 10 감소
if ss_muteki % 2 == 0: # 무적 상태에서 깜빡이기 위한 if 문
scrn.blit(img_sship[3], [ss_x - 8, ss_y + 40 + (tmr % 3) *2]) # 엔진 불꽃 그리기
scrn.blit(img_sship[ss_d], [ss_x - 37, ss_y - 48]) # 플레이어 기체 그리기
if ss_muteki > 0: # 무적 상태라면
ss_muteki = ss_muteki - 1 # ss_muteki 값 감소
return # 함수에서 벗어남(적과 히트 체크 미수행)
for i in range(ENEMY_MAX): # 적 기체외 히트 체크 수행
if emy_f[i] == True: # 적 기체와 히트 체크
w = img_enemy[emy_type[i]].get_width()
h = img_enemy[emy_type[i]].get_height()
r = int((w + h) / 4 + (74 + 96) / 4)
if get_dis(emy_x[i], emy_y[i], ss_x, ss_y) < r * r: # 적 기체와 접촉한 경우
set_effect(ss_x, ss_y) # 폭발 연출 설정
ss_shield = ss_shield - 10 # 실드량 감소
if ss_shield <= 0: # ss_shield 값이 0 이하이면
ss_shield = 0 # ss_shield 값에 0 대입
if ss_muteki == 0: # 무적 상태가 아니면
ss_muteki = 60 # 무적 상태로 설정
emy_f[i] = False
def set_missile(typ): # 플레이어 기체 발사 탄환 설정
global msl_no
if typ == 0: # 단발
msl_f[msl_no] = True # 탄환 발사 플래그 True 설정
msl_x[msl_no] = ss_x # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
msl_y[msl_no] = ss_y - 50
msl_a[msl_no] = 270 # 탄환 발사 각도
msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산
if typ == 10: # 탄막
for a in range(160, 390, 10):
msl_f[msl_no] = True # 탄환 발사 플래그 True 설정
msl_x[msl_no] = ss_x # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
msl_y[msl_no] = ss_y - 50
msl_a[msl_no] = a # 탄환 발사 각도
msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산
def move_missile(scrn): # 탄환 이동
for i in range(MISSILE_MAX):
if msl_f[i] == True: # 탄환이 발사된 상태라면
msl_x[i] = msl_x[i] + 36 * math.cos(math.radians(msl_a[i])) # X, Y 좌표 계산
msl_y[i] = msl_y[i] + 36 * math.sin(math.radians(msl_a[i]))
img_rz = pygame.transform.rotozoom(img_weapon, -90 - msl_a[i], 1.0) # 날아가는 각도의 회전 이미지 생성
scrn.blit(img_rz, [msl_x[i] - img_rz.get_width() / 2, msl_y[i] - img_rz.get_height() / 2]) # 탄환 이미지 그리기
if msl_y[i] < 0 or msl_x[i] < 0 or msl_x[i] > 960: # 탄환이 화면 밖으로 나가면
msl_f[i] = False # 탄환 삭제
def bring_enemy(): # 적 기체 등장
if tmr % 30 == 0: # 이 타이밍에서
set_enemy(random.randint(20, 940), LINE_T, 90, 1, 6) # 일반 기체 1기 등장
def set_enemy(x, y, a, ty, sp): # 적 기체 설정
global emy_no
while True:
if emy_f[emy_no] == False: # 비어있는 리스트라면
emy_f[emy_no] = True # 플래그 설정
emy_x[emy_no] = x # X, Y 좌표 대입
emy_y[emy_no] = y
emy_a[emy_no] = a # 각도 대입
emy_type[emy_no] = ty # 적 종류 대입
emy_speed[emy_no] = sp # 적 속도 대입
break
emy_no = (emy_no + 1) % ENEMY_MAX # 다음 설정을 위한 번호 계산
def move_enemy(scrn): # 적 기체 이동
global ss_shield
for i in range(ENEMY_MAX):
if emy_f[i] == True: # 적 기체가 존재한다면
ang = -90 - emy_a[i] # ang에 이미지 회전 각도 대입
png = emy_type[i] # png에 이미지 번호 대입
emy_x[i] = emy_x[i] + emy_speed[i] * math.cos(math.radians(emy_a[i])) # X, Y 좌표 변화
emy_y[i] = emy_y[i] + emy_speed[i] * math.sin(math.radians(emy_a[i]))
if emy_type[i] == 1 and emy_y[i] > 360: # 적 기체의 Y 좌표가 360을 넘었다면
set_enemy(emy_x[i], emy_y[i], 90, 0, 8) # 탄환 발사
emy_a[i] = -45 # 방향 변경
emy_speed[i] = 16 # 속도 변경
if emy_x[i] < LINE_L or LINE_R < emy_x[i] or emy_y[i] < LINE_T or LINE_B < emy_y[i]: # 화면 상하좌우에서 벗어났다면
emy_f[i] = False # 적 기체 삭제
if emy_type[i] != EMY_BULLET: # 플레이어 기체 발사 탄환과 히트 체크
w = img_enemy[emy_type[i]].get_width() # 적 기체 이미지 폭(픽셀 수)
h = img_enemy[emy_type[i]].get_height() # 적 기체 이미지 높이(픽셀 수)
r = int((w + h) / 4) + 12 # 히트 체크에 사용할 거리 계산
for n in range(MISSILE_MAX):
if msl_f[n] == True and get_dis(emy_x[i], emy_y[i], msl_x[n], msl_y[n]) < r * r: # 플레이어 기체 탄환과 접촉 여부 판단
msl_f[n] = False # 탄환 삭제
set_effect(emy_x[i], emy_y[i]) # 폭발 이펙트
emy_f[i] = False # 적 기체 삭제
if ss_shield < 100: # 플레이어 실드량이 100 미만이면
ss_shield = ss_shield + 1 # 실드량 증가
img_rz = pygame.transform.rotozoom(img_enemy[png], ang, 1.0)
scrn.blit(img_rz, [emy_x[i] - img_rz.get_width() / 2, emy_y[i] - img_rz.get_height() / 2])
def set_effect(x, y): # 폭발 설정
global eff_no
eff_p[eff_no] = 1 # 폭발 연출 이미지 번호 대입
eff_x[eff_no] = x # 폭발 연출 X, Y 좌표 대입
eff_y[eff_no] = y
eff_no = (eff_no + 1) % EFFECT_MAX # 다음 설정을 위한 번호 계산
def draw_effect(scrn): # 폭발 연출
for i in range(EFFECT_MAX):
if eff_p[i] > 0: # 폭발 연출 중이면
scrn.blit(img_explode[eff_p[i]], [eff_x[i] - 48, eff_y[i] - 48]) # 폭발 연출 표시
eff_p[i] = eff_p[i] + 1 # eff_p 값 1 증가
if eff_p[i] == 6: # eff_p가 6이 되었다면
eff_p[i] = 0 # eff_p에 0 대입 후 연출 종료
def main():
global tmr, bg_y
pygame.init()
pygame.display.set_caption('Galaxy Lancer')
screen = pygame.display.set_mode((960, 720))
clock = pygame.time.Clock()
while True:
tmr = tmr + 1
for e in pygame.event.get():
if e.type == QUIT:
pygame.quit()
sys.exit()
if e.type == KEYDOWN:
if e.key == K_F1:
screen = pygame.display.set_mode((960, 720), pygame.FULLSCREEN)
if e.key == K_F2 or e.key == K_ESCAPE:
screen = pygame.display.set_mode((960, 720))
# 배경 스크롤
bg_y = (bg_y + 16) % 720 # 배경 스크롤 위치 계산
screen.blit(img_galaxy, [0, bg_y - 720]) # 배경 그리기(위쪽)
screen.blit(img_galaxy, [0, bg_y]) # 배경 그리기(아래쪽)
key = pygame.key.get_pressed() # key에 모든 키 상태를 대입
move_starship(screen, key) # 플레이어 기체 이동
move_missile(screen) # 플레이어 탄환 이동
bring_enemy() # 적 기체 등장
move_enemy(screen) # 적 기체 이동
draw_effect(screen) # 폭발 연출
screen.blit(img_shield, [40, 680]) # 실드 화면 그리기
pygame.draw.rect(screen, (64, 32, 32), [40 + ss_shield * 4, 680, (100 - ss_shield) * 4, 12]) # 감소한 실드를 사각형으로 칠함
pygame.display.update()
clock.tick(30)
if __name__ == '__main__':
main()
추가 및 변경된 점 : move_starship() 함수에서 적 기체와 접촉했을 때 무적 설정, 실드량 감소 부분 추가, move_enemy() 함수에 적 격추 시 실드량 회복 부분 추가
적의 탄환이나 기체에 닿으면 실드가 감소하고, 플레이어 기체가 깜빡이며, 그 동안 데미지를 받지 않는다. 실드가 깎여 있을 때 적을 격추하면 실드가 회복된다.
ss_shield로 실드량, ss_muteki로 무적 상태 시간을 관리한다.
if ss_muteki > 0: # 무적 상태라면
ss_muteki = ss_muteki - 1 # ss_muteki 값 감소
return # 함수에서 벗어남(적과 히트 체크 미수행)
for i in range(ENEMY_MAX): # 적 기체외 히트 체크 수행
if emy_f[i] == True: # 적 기체와 히트 체크
w = img_enemy[emy_type[i]].get_width()
h = img_enemy[emy_type[i]].get_height()
r = int((w + h) / 4 + (74 + 96) / 4)
if get_dis(emy_x[i], emy_y[i], ss_x, ss_y) < r * r: # 적 기체와 접촉한 경우
set_effect(ss_x, ss_y) # 폭발 연출 설정
ss_shield = ss_shield - 10 # 실드량 감소
if ss_shield <= 0: # ss_shield 값이 0 이하이면
ss_shield = 0 # ss_shield 값에 0 대입
if ss_muteki == 0: # 무적 상태가 아니면
ss_muteki = 60 # 무적 상태로 설정
emy_f[i] = False
if ss_muteki > 0이라는 조건 분기에서 무적 상태인 경우에는 ss_muteki 값을 감소시키고 return 명령으로 함수를 빠져 나와 히트 체크를 수행하지 않는다.
import pygame
import sys
import math
import random
from pygame.locals import *
# 색 정의
BLACK = (0, 0, 0)
SILVER = (192, 208, 224)
RED = (255, 0, 0)
CYAN = (0, 224, 255)
# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/galaxy.png')
img_sship = [
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_l.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_r.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/starship_burner.png')
]
img_weapon = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/bullet.png')
img_shield = pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/shield.png')
img_enemy = [
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/enemy0.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/enemy1.png')
]
img_explode = [
None,
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion1.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion2.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion3.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion4.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/explosion5.png')
]
img_title = [
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/nebula.png'),
pygame.image.load('Python_workspace/python_game/Chapter7/img_gl/logo.png')
]
idx = 0
tmr = 0
score = 0
bg_y = 0
ss_x = 0 # 플레이어 기체의 X, Y 좌표
ss_y = 0
ss_d = 0 # 플레이어 기체의 기울기 변수
ss_shield = 0 # 플레이어 기체의 실드량 변수
ss_muteki = 0 # 플레이어 기체의 무적 상태 변수
key_spc = 0 # 스페이스 키를 눌렀을 때 사용하는 변수
key_z = 0 # Z 키를 눌렀을 때 사용할 변수
MISSILE_MAX = 200 # 플레이어가 발사한 최대 탄환 수 정의
msl_no = 0 # 탄환 발사에 사용할 리스트 인덱스 변수
msl_f = [False] * MISSILE_MAX # 탄환을 발사 중인지 관리하는 플래그 리스트
msl_x = [0] * MISSILE_MAX # 탄환의 X, Y 좌표 리스트
msl_y = [0] * MISSILE_MAX
msl_a = [0] * MISSILE_MAX # 탄환이 날아가는 각도 리스트
ENEMY_MAX = 100 # 적 최대 수 정의
emy_no = 0 # 적 등장시 사용할 리스트 인덱스 변수
emy_f = [False] * ENEMY_MAX # 적 등장 여부 관리 플래그 리스트
emy_x = [0] * ENEMY_MAX # 적 X, Y 좌표 리스트
emy_y = [0] * ENEMY_MAX
emy_a = [0] * ENEMY_MAX # 적의 비행 각도 리스트
emy_type = [0] * ENEMY_MAX # 적의 종류 리스트
emy_speed = [0] * ENEMY_MAX # 적 속도 리스트
EMY_BULLET = 0 # 적의 탄환 번호 관리 상수
LINE_T = -80 # 적이 나타나는(사라지는) 위쪽 좌표
LINE_B = 800 # 적이 나타나는(사라지는) 아래쪽 좌표
LINE_L = -80 # 적이 나타나는(사라지는) 왼쪽 좌표
LINE_R = 1040 # 적이 나타나는(사라지는) 오른쪽 좌표
EFFECT_MAX = 100 # 폭발 연출 최대 수 정의
eff_no = 0 # 폭발 연출 시 사용할 리스트 인덱스 변수
eff_p = [0] * EFFECT_MAX # 폭발 연출 이미지 번호 리스트
eff_x = [0] * EFFECT_MAX # 폭발 연출 X, Y 좌표 리스트
eff_y = [0] * EFFECT_MAX
def get_dis(x1, y1, x2, y2): # 두 점 사이 거리 계산
return ((x1 -x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
def draw_text(scrn, txt, x, y, siz, col): # 문자 표시
fnt = pygame.font.Font(None, siz)
sur = fnt.render(txt, True, col)
x = x - sur.get_width() / 2
y = y - sur.get_height() / 2
scrn.blit(sur, [x, y])
def move_starship(scrn, key): # 플레이어 기체 이동
global idx, tmr, ss_x, ss_y, ss_d, ss_shield, ss_muteki, key_spc, key_z
ss_d = 0 # 기체 기울기 변수에 0(기울지 않음 대입)
if key[K_UP] == 1: # 방향 키를 눌렀다면
ss_y = ss_y - 20
if ss_y < 80: # 화면 밖으로 나가지 않도록 조정
ss_y = 80
if key[K_DOWN] == 1:
ss_y = ss_y + 20
if ss_y > 640:
ss_y = 640
if key[K_LEFT] == 1:
ss_d = 1 # 기체 기울기 변수에 1(왼쪽) 대입
ss_x = ss_x - 20
if ss_x < 40:
ss_x = 40
if key[K_RIGHT] == 1:
ss_d = 2 # 기체 기울기 변수에 2(오른쪽) 대입
ss_x = ss_x + 20
if ss_x > 920:
ss_x = 920
key_spc = (key_spc + 1) * key[K_SPACE] # 스페이스 키를 누르는 동안 변수 값 증가
if key_spc % 5 == 1: # 스페이스 키를 처음 누른 후, 5 프레임마다
set_missile(0) # 탄환 발사
key_z = (key_z + 1) * key[K_z] # Z 키를 누르는 동안 변수 값 증가
if key_z == 1 and ss_shield > 10: # 1 번 눌렀을 때 실드량이 10보다 크다면
set_missile(10) # 탄막 치기
ss_shield = ss_shield - 10 # 실드량 10 감소
if ss_muteki % 2 == 0: # 무적 상태에서 깜빡이기 위한 if 문
scrn.blit(img_sship[3], [ss_x - 8, ss_y + 40 + (tmr % 3) *2]) # 엔진 불꽃 그리기
scrn.blit(img_sship[ss_d], [ss_x - 37, ss_y - 48]) # 플레이어 기체 그리기
if ss_muteki > 0: # 무적 상태라면
ss_muteki = ss_muteki - 1 # ss_muteki 값 감소
return # 함수에서 벗어남(적과 히트 체크 미수행)
elif idx == 1: # 무적 상태가 아니고, idx가 1이면
for i in range(ENEMY_MAX): # 적 기체외 히트 체크 수행
if emy_f[i] == True: # 적 기체와 히트 체크
w = img_enemy[emy_type[i]].get_width()
h = img_enemy[emy_type[i]].get_height()
r = int((w + h) / 4 + (74 + 96) / 4)
if get_dis(emy_x[i], emy_y[i], ss_x, ss_y) < r * r: # 적 기체와 접촉한 경우
set_effect(ss_x, ss_y) # 폭발 연출 설정
ss_shield = ss_shield - 10 # 실드량 감소
if ss_shield <= 0: # ss_shield 값이 0 이하이면
ss_shield = 0 # ss_shield 값에 0 대입
idx = 2 # 게임 오버로 이동
tmr = 0
if ss_muteki == 0: # 무적 상태가 아니면
ss_muteki = 60 # 무적 상태로 설정
emy_f[i] = False
def set_missile(typ): # 플레이어 기체 발사 탄환 설정
global msl_no
if typ == 0: # 단발
msl_f[msl_no] = True # 탄환 발사 플래그 True 설정
msl_x[msl_no] = ss_x # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
msl_y[msl_no] = ss_y - 50
msl_a[msl_no] = 270 # 탄환 발사 각도
msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산
if typ == 10: # 탄막
for a in range(160, 390, 10):
msl_f[msl_no] = True # 탄환 발사 플래그 True 설정
msl_x[msl_no] = ss_x # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
msl_y[msl_no] = ss_y - 50
msl_a[msl_no] = a # 탄환 발사 각도
msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산
def move_missile(scrn): # 탄환 이동
for i in range(MISSILE_MAX):
if msl_f[i] == True: # 탄환이 발사된 상태라면
msl_x[i] = msl_x[i] + 36 * math.cos(math.radians(msl_a[i])) # X, Y 좌표 계산
msl_y[i] = msl_y[i] + 36 * math.sin(math.radians(msl_a[i]))
img_rz = pygame.transform.rotozoom(img_weapon, -90 - msl_a[i], 1.0) # 날아가는 각도의 회전 이미지 생성
scrn.blit(img_rz, [msl_x[i] - img_rz.get_width() / 2, msl_y[i] - img_rz.get_height() / 2]) # 탄환 이미지 그리기
if msl_y[i] < 0 or msl_x[i] < 0 or msl_x[i] > 960: # 탄환이 화면 밖으로 나가면
msl_f[i] = False # 탄환 삭제
def bring_enemy(): # 적 기체 등장
if tmr % 30 == 0: # 이 타이밍에서
set_enemy(random.randint(20, 940), LINE_T, 90, 1, 6) # 일반 기체 1기 등장
def set_enemy(x, y, a, ty, sp): # 적 기체 설정
global emy_no
while True:
if emy_f[emy_no] == False: # 비어있는 리스트라면
emy_f[emy_no] = True # 플래그 설정
emy_x[emy_no] = x # X, Y 좌표 대입
emy_y[emy_no] = y
emy_a[emy_no] = a # 각도 대입
emy_type[emy_no] = ty # 적 종류 대입
emy_speed[emy_no] = sp # 적 속도 대입
break
emy_no = (emy_no + 1) % ENEMY_MAX # 다음 설정을 위한 번호 계산
print(emy_no)
def move_enemy(scrn): # 적 기체 이동
global idx, tmr, score, ss_shield
for i in range(ENEMY_MAX):
if emy_f[i] == True: # 적 기체가 존재한다면
ang = -90 - emy_a[i] # ang에 이미지 회전 각도 대입
png = emy_type[i] # png에 이미지 번호 대입
emy_x[i] = emy_x[i] + emy_speed[i] * math.cos(math.radians(emy_a[i])) # X, Y 좌표 변화
emy_y[i] = emy_y[i] + emy_speed[i] * math.sin(math.radians(emy_a[i]))
if emy_type[i] == 1 and emy_y[i] > 360: # 적 기체의 Y 좌표가 360을 넘었다면
set_enemy(emy_x[i], emy_y[i], 90, 0, 8) # 탄환 발사
emy_a[i] = -45 # 방향 변경
emy_speed[i] = 16 # 속도 변경
if emy_x[i] < LINE_L or LINE_R < emy_x[i] or emy_y[i] < LINE_T or LINE_B < emy_y[i]: # 화면 상하좌우에서 벗어났다면
emy_f[i] = False # 적 기체 삭제
if emy_type[i] != EMY_BULLET: # 플레이어 기체 발사 탄환과 히트 체크
w = img_enemy[emy_type[i]].get_width() # 적 기체 이미지 폭(픽셀 수)
h = img_enemy[emy_type[i]].get_height() # 적 기체 이미지 높이(픽셀 수)
r = int((w + h) / 4) + 12 # 히트 체크에 사용할 거리 계산
for n in range(MISSILE_MAX):
if msl_f[n] == True and get_dis(emy_x[i], emy_y[i], msl_x[n], msl_y[n]) < r * r: # 플레이어 기체 탄환과 접촉 여부 판단
msl_f[n] = False # 탄환 삭제
set_effect(emy_x[i], emy_y[i]) # 폭발 이펙트
score = score + 100 # 점수 증가
emy_f[i] = False # 적 기체 삭제
if ss_shield < 100: # 플레이어 실드량이 100 미만이면
ss_shield = ss_shield + 1 # 실드량 증가
img_rz = pygame.transform.rotozoom(img_enemy[png], ang, 1.0)
scrn.blit(img_rz, [emy_x[i] - img_rz.get_width() / 2, emy_y[i] - img_rz.get_height() / 2])
def set_effect(x, y): # 폭발 설정
global eff_no
eff_p[eff_no] = 1 # 폭발 연출 이미지 번호 대입
eff_x[eff_no] = x # 폭발 연출 X, Y 좌표 대입
eff_y[eff_no] = y
eff_no = (eff_no + 1) % EFFECT_MAX # 다음 설정을 위한 번호 계산
def draw_effect(scrn): # 폭발 연출
for i in range(EFFECT_MAX):
if eff_p[i] > 0: # 폭발 연출 중이면
scrn.blit(img_explode[eff_p[i]], [eff_x[i] - 48, eff_y[i] - 48]) # 폭발 연출 표시
eff_p[i] = eff_p[i] + 1 # eff_p 값 1 증가
if eff_p[i] == 6: # eff_p가 6이 되었다면
eff_p[i] = 0 # eff_p에 0 대입 후 연출 종료
def main():
global idx, tmr, score, bg_y, ss_x, ss_y, ss_d, ss_shield, ss_muteki
pygame.init()
pygame.display.set_caption('Galaxy Lancer')
screen = pygame.display.set_mode((960, 720))
clock = pygame.time.Clock()
while True:
tmr = tmr + 1
for e in pygame.event.get():
if e.type == QUIT:
pygame.quit()
sys.exit()
if e.type == KEYDOWN:
if e.key == K_F1:
screen = pygame.display.set_mode((960, 720), pygame.FULLSCREEN)
if e.key == K_F2 or e.key == K_ESCAPE:
screen = pygame.display.set_mode((960, 720))
# 배경 스크롤
bg_y = (bg_y + 16) % 720 # 배경 스크롤 위치 계산
screen.blit(img_galaxy, [0, bg_y - 720]) # 배경 그리기(위쪽)
screen.blit(img_galaxy, [0, bg_y]) # 배경 그리기(아래쪽)
key = pygame.key.get_pressed() # key에 모든 키 상태를 대입
if idx == 0: # 타이틀
img_rz = pygame.transform.rotozoom(img_title[0], -tmr % 360, 1.0) # 로고 뒤에서 회전하는 소용돌이 이미지
screen.blit(img_rz, [480 - img_rz.get_width() / 2, 280 - img_rz.get_height() / 2])
screen.blit(img_title[1], [70, 160])
draw_text(screen, 'Press [SPACE] to start!', 480, 600, 50, SILVER)
if key[K_SPACE] == 1: # 스페이스 키를 눌렀다면 게임 관련 변수 초기 값 대입
idx = 1
tmr = 0
score = 0
score = 0
ss_x = 480
ss_y = 600
ss_d = 0
ss_shield = 100
ss_muteki = 0
for i in range(ENEMY_MAX):
emy_f[i] = False
for i in range(MISSILE_MAX):
msl_f[i] = False
if idx == 1: # 게임 플레이 중
move_starship(screen, key) # 플레이어 기체 이동
move_missile(screen) # 플레이어 탄환 이동
bring_enemy() # 적 기체 등장
move_enemy(screen) # 적 기체 이동
if tmr == 30 * 60: # 약 1분 뒤에
idx = 3 # 게임 클리어로 이동
tmr = 0
if idx == 2: # 게임 오버
move_missile(screen)
move_enemy(screen)
draw_text(screen, 'GAME OVER', 480, 300, 80, SILVER)
if tmr == 150:
idx = 0 # 타이틀 화면으로 이동
tmr = 0
if idx == 3: # 게임 클리어
move_starship(screen, key)
move_missile(screen)
draw_text(screen, 'GAME CLEAR', 480, 300, 80, SILVER)
if tmr == 150:
idx = 0 # 타이틀 화면으로 이동
tmr = 0
draw_effect(screen)
draw_text(screen, 'SCORE ' + str(score), 200, 30, 50, SILVER)
if idx != 0: # 타이틀 화면이 아니면
screen.blit(img_shield, [40, 680]) # 실드를 그림
pygame.draw.rect(screen, (64, 32, 32), [40 + ss_shield * 4, 680, (100 - ss_shield) * 4, 12])
pygame.display.update()
clock.tick(30)
if __name__ == '__main__':
main()
추가 및 변경된 점 : draw_text() 함수 추가, move_starship() 함수에 게임 플레이 중에만 히트 체크하도록 하고 실드가 0이되면 게임 오버로 이동하는 부분 추가, move_enemy() 함수에 점수 증가 부분 추가, main() 함수에 idx와 tmr을 사용하여 구현
약 1분동안 버티면 게임 클리어, 도중에 실드가 0이되면 게임 오버가 된다.
게임 흐름은 idx와 tmr로 관리한다.