Skip to content

Latest commit

 

History

History
564 lines (477 loc) · 24.5 KB

220104.md

File metadata and controls

564 lines (477 loc) · 24.5 KB

Day 88

파이썬으로 배우는 게임 개발 실전편

Chapter 6

Pygame으로 고속 스크롤 구현하기

import pygame
import sys

# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\galaxy.png')

bg_y = 0

def main():
    global bg_y

    pygame.init()
    pygame.display.set_caption('Galaxy Lancer')
    screen = pygame.display.set_mode((960, 720))
    clock = pygame.time.Clock()

    while True:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_F1:
                    screen = pygame.display.set_mode((960, 720), pygame.FULLSCREEN)
                if e.key == pygame.K_F2 or e.key == pygame.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]) # 배경 그리기(아래쪽)

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

if __name__ == '__main__':
    main()

배경이 빠르게 스크롤된다.

bg_y라는 변수로 배경을 스크롤하는 좌표를 관리하고 'bg_y = (bg_y + 16) % 720'이라는 계산식을 통해 값을 16씩 증가시키다가 720이 되면 0으로 되돌린다.

플레이어 기체 움직이기

import pygame
import sys
from pygame.locals import *

# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\galaxy.png')
img_sship = [
    pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\starship.png'),
    pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\starship_l.png'),
    pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\starship_r.png'),
    pygame.image.load('Python_workspace\python_game\Chapter6\img_gl\starship_burner.png')
]

tmr = 0
bg_y = 0

ss_x = 480 # 플레이어 기체의 X 좌표
ss_y = 360 # 플레이어 기체의 Y 좌표
ss_d = 0 # 플레이어 기체의 기울기 변수

def move_starship(scrn, key): # 플레이어 기체 이동
    global ss_x, ss_y, ss_d
    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
    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]) # 플레이어 기체 그리기

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) # 플레이어 기체 이동

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

if __name__ == '__main__':
    main()

key 변수에 모든 키 상태를 대입하고 move_starship 함수에 전달하여 방향 키를 눌렀으면 해당 방향으로 움직인다. 움직이면서 화면 밖으로 나가지 않도록 if 문으로 조건을 설정한다.

플레이어 기체는 가로 74 픽셀, 세로 96 픽셀이다. ss_x와 ss_y는 기체의 중심점이기 때문에 플레이어 기체를 그릴 때는 (ss_x - 37, ss_y - 48) 좌표에 그린다.

ss_x와 ss_y를 기체 중심점으로 한 이유는 이후에 히트체크 계산을 쉽게하기 위해서이다.

불꽃 이미지는 1장이지만 타이머 변수를 이용해 표시할 Y 좌표를 'ss_y + 40 + (tmr % 3) * 2'로 계산해서 뿜어져 나오는 형태로 표현할 수 있다.

탄환 발사하기

import pygame
import sys
from pygame.locals import *

# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/galaxy.png')
img_sship = [
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_l.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_r.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_burner.png')
]
img_weapon = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/bullet.png')

tmr = 0
bg_y = 0

ss_x = 480      # 플레이어 기체의 X 좌표
ss_y = 360      # 플레이어 기체의 Y 좌표
ss_d = 0        # 플레이어 기체의 기울기 변수

msl_f = False   # 탄환을 발사 중인지 관리하는 변수(플래그)
msl_x = 0       # 탄환의 X, Y 좌표
msl_y = 0

def move_starship(scrn, key):   # 플레이어 기체 이동
    global ss_x, ss_y, ss_d
    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
    if key[K_SPACE] == 1:       # 스페이스 누르면 탄환 발사
        set_missile()
    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])              # 플레이어 기체 그리기

def set_missile():      # 플레이어 기체 발사 탄환 설정
    global msl_f, msl_x, msl_y
    if msl_f == False:  # 탄환이 발사되지 않았다면
        msl_f = True    # 탄환 발사 플래그 True 설정
        msl_x = ss_x    # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
        msl_y = ss_y - 50

def move_missile(scrn):     # 탄환 이동
    global msl_f, msl_y
    if msl_f == True:       # 탄환이 발사된 상태라면
        msl_y = msl_y - 36  # Y 좌표 계산
        scrn.blit(img_weapon, [msl_x - 10, msl_y - 32]) # 탄환 이미지 그리기
        if msl_y < 0:       # 탄환이 화면 밖으로 나가면
            msl_f = False   # 탄환 삭제


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)                        # 플레이어 탄환 이동

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

if __name__ == '__main__':
    main()

탄환이 발사되어 날아가는 중이라면 True, 발사되지 않은 상태라면 False로 표현한다.

화면 밖으로 탄환이 나가면 False가 되어 다시 탄환을 발사할 수 있게 된다.

여러 탄환 발사하기

import pygame
import sys
from pygame.locals import *

# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/galaxy.png')
img_sship = [
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_l.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_r.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_burner.png')
]
img_weapon = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/bullet.png')

tmr = 0
bg_y = 0

ss_x = 480      # 플레이어 기체의 X 좌표
ss_y = 360      # 플레이어 기체의 Y 좌표
ss_d = 0        # 플레이어 기체의 기울기 변수
key_spc = 0     # 스페이스 키를 눌렀을 때 사용하는 변수

MISSILE_MAX = 200               # 플레이어가 발사한 최대 탄환 수 정의
msl_no = 0                      # 탄환 발사에 사용할 리스트 인덱스 변수
msl_f = [False] * MISSILE_MAX   # 탄환을 발사 중인지 관리하는 플래그 리스트
msl_x = [0] * MISSILE_MAX       # 탄환의 X, Y 좌표 리스트
msl_y = [0] * MISSILE_MAX

def move_starship(scrn, key):   # 플레이어 기체 이동
    global ss_x, ss_y, ss_d, key_spc
    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()                       # 탄환 발사
    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])              # 플레이어 기체 그리기

def set_missile():      # 플레이어 기체 발사 탄환 설정
    global msl_no
    if msl_f[msl_no] == False:  # 탄환이 발사되지 않았다면
        msl_f[msl_no] = True    # 탄환 발사 플래그 True 설정
        msl_x[msl_no] = ss_x    # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
        msl_y[msl_no] = ss_y - 50
        msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산

def move_missile(scrn):     # 탄환 이동
    for i in range(MISSILE_MAX):
        if msl_f[i] == True:            # 탄환이 발사된 상태라면
            msl_y[i] = msl_y[i] - 36    # Y 좌표 계산
            scrn.blit(img_weapon, [msl_x[i] - 10, msl_y[i] - 32]) # 탄환 이미지 그리기
            if msl_y[i] < 0:            # 탄환이 화면 밖으로 나가면
                msl_f[i] = False        # 탄환 삭제


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)                        # 플레이어 탄환 이동

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

if __name__ == '__main__':
    main()

스페이스 키를 누르고 있으면 탄환을 연속해서 발사한다.

여러 탄환을 관리하기 위해서 이번에는 msl_f, msl_x, msl_y라는 리스트로 관리한다.
msl_f[n]이 True라면 n번째 탄환이 존재하는 것이고, False라면 n번째 탄환은 존재하지 않는 것이다.

탄환을 설정하는 함수인 set_missile 함수를 보자

def set_missile():      # 플레이어 기체 발사 탄환 설정
    global msl_no
    if msl_f[msl_no] == False:  # 탄환이 발사되지 않았다면
        msl_f[msl_no] = True    # 탄환 발사 플래그 True 설정
        msl_x[msl_no] = ss_x    # 탄환의 X, Y 좌표 대입(플레이어 기체 앞 끝)
        msl_y[msl_no] = ss_y - 50
        msl_no = (msl_no + 1) % MISSILE_MAX # 다음 설정을 위한 번호 계산

msl_no라는 변수를 탄환을 관리하는 리스트의 인덱스로 지정한다.
그리고 set_missile 함수가 호출될 때마다 msl_no = (msl_no + 1) % MISSILE_MAX 계산식을 통해 다음 리스트의 인덱스 값을 계산한다.

탄환 이동을 담당하는 함수인 move_missile 함수를 보자

def move_missile(scrn):     # 탄환 이동
    for i in range(MISSILE_MAX):
        if msl_f[i] == True:            # 탄환이 발사된 상태라면
            msl_y[i] = msl_y[i] - 36    # Y 좌표 계산
            scrn.blit(img_weapon, [msl_x[i] - 10, msl_y[i] - 32]) # 탄환 이미지 그리기
            if msl_y[i] < 0:            # 탄환이 화면 밖으로 나가면
                msl_f[i] = False        # 탄환 삭제

반복 구문을 활용해 모든 탄환을 리스트로 처리한다.

결과적으로 스페이스키를 누르고 있으면 set_missile 함수를 실행하고 리스트에 발사하는 탄환을 설정한 후, 다음 리스트 번호를 계산해둔다. 또한 새로운 리스트에 탄환을 설정하고 다음 리스트 번호를 계산한다.

key_spc = (key_spc + 1) * key[K_SPACE]  # 스페이스 키를 누르는 동안 변수 값 증가
if key_spc % 5 == 1:                    # 스페이스 키를 처음 누른 후, 5 프레임마다
    set_missile()                       # 탄환 발사

이 부분을 통해 탄환이 일정한 간격으로 발사된다.

스페이스 키를 누르고 있으면 key_spc 값이 계속 증가하는데 값이 1, 6, 11, 16 ... 인 경우에 탄환이 발사된다.

스페이스를 1번 누르면 key_spc가 1이되어 즉시 발사되지만 계속 눌려 있는 상태라면 5프레임마다 발사된다. 그래서 스페이스 키를 연타하면 누르고 있는 경우보다 많은 탄환을 발사할 수 있다.

발사 간격을 줄이려면 % n의 숫자를 줄이면 된다.

탄막 펼치기

import pygame
import sys
import math
from pygame.locals import *

# 이미지 로딩
img_galaxy = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/galaxy.png')
img_sship = [
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_l.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_r.png'),
    pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/starship_burner.png')
]
img_weapon = pygame.image.load('Python_workspace/python_game/Chapter6/img_gl/bullet.png')

tmr = 0
bg_y = 0

ss_x = 480      # 플레이어 기체의 X 좌표
ss_y = 360      # 플레이어 기체의 Y 좌표
ss_d = 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       # 탄환이 날아가는 각도 리스트

def move_starship(scrn, key):   # 플레이어 기체 이동
    global ss_x, ss_y, ss_d, 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:                          # 1 번 눌렀을 때
        set_missile(10)                     # 탄막 치기
    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])              # 플레이어 기체 그리기

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 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)                        # 플레이어 탄환 이동

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

if __name__ == '__main__':
    main()

삼각함수를 사용해 여러 탄환을 방사형으로 발사한다.

msl_a 리스트로 탄환이 날아가는 각도를 관리한다.

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 # 다음 설정을 위한 번호 계산

set_missile 함수는 인수가 0이면 단발, 10인 경우 탄막을 설정하도록 했다.

인수 10을 전달하면 160도부터 380도 사이에서 10도마다 탄환이 날아가도록 한다.

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                                                                        # 탄환 삭제

move_missile 함수는 삼각함수로 탄환의 X축 방향, Y축 방향 이동량을 계산하고 탄환의 좌표를 변화시킨다.

'36 * math.cos(math.radians(msl_a[i]))'의 의미는
'픽셀 수 * math.cos(각도)가 X 축 방향의 좌표 변화량'이다.

rotozoom 명령의 각도는 삼각함수와 반대 방향이므로 -90 - msl_a[i]로 지정해 삼각함수의 각도와 같은 방향으로 탄환 이미지를 생성한다.