Skip to content

Latest commit

 

History

History
201 lines (168 loc) · 8.75 KB

211220.md

File metadata and controls

201 lines (168 loc) · 8.75 KB

Day 75

파이썬으로 배우는 게임 개발 입문편

Pygame

턴제 전투

# 턴제 전투
import pygame
import sys
import random
from pygame.locals import * # 이벤트 종류와 키보드 상수 등을 pygame.을 생략할 수 있음

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

imgBtlBG = pygame.image.load('Python_workspace\mini_game\image_dir\\btlbg.png') # 전투 배경 이미지 로딩
imgEffect = pygame.image.load('Python_workspace\mini_game\image_dir\effect_a.png') # 공격 효과 이미지 로딩
imgEnemy = pygame.image.load('Python_workspace\mini_game\image_dir\enemy4.png') # 적 이미지 로딩

emy_x = 440 - imgEnemy.get_width() / 2 # 이미지 폭으로부터 표시 위치(X 좌표) 계산
emy_y = 560 - imgEnemy.get_height() # 이미지 높이로부터 표시 위치(Y 좌표) 계산
emy_step = 0 # 적 이동 관리 변수
emy_blink = 0 # 적 깜빡임 효과 관리 변수
dmg_eff = 0 # 화면 흔들림 효과 관리 변수
COMMAND = ['[A]ttack', '[P]otion', '[B]laze gem', '[R]un'] # 전투 명령어 리스트

message = [''] * 10 # 전투 메시지 입력 리스트
def init_message(): # 메시지 초기화 함수
    for i in range(10):
        message[i] = '' # 리스트에 빈 문자열 대입

def set_message(msg): # 메시지 설정 함수
    for i in range(10):
        if message[i] == '': # 문자열이 설정되어 있지 않다면
            message[i] = msg # 새로운 문자열 대입
            return # 함수 처리 종료
    for i in range(9):
        message[i] = message[i + 1] # 메시지를 한 문자씩 슬라이스
    message[9] = msg # 마지막 행에 새로운 문자열 대입

def draw_text(bg, txt, x, y, fnt, col): # 문자열 그림자 처리 함수
    sur = fnt.render(txt, True, BLACK) # 검은 색으로 문자열을 표시할 Surface
    bg.blit(sur, [x + 1, y + 2]) # 지정 좌표의 약간 오른쪽 아래에 문자열 전송
    sur = fnt.render(txt, True, col) # 지정한 색으로 문자열을 표시할 Surface
    bg.blit(sur, [x, y]) # 지정 좌표에 문자열 전송

def draw_battle(bg, fnt): # 전투 화면 표시 함수
    global emy_blink, dmg_eff
    bx = 0 # 배경 표시 위치 X 좌표
    by = 0 # 배경 표시 위치 Y 좌표
    if dmg_eff > 0: # 화면 흔들림 효과 변수가 설정되어 있다면
        dmg_eff -= 1 # 해당 변수값 1 감소
        bx = random.randint(-20, 20) # 난수로 X 좌표 결정
        by = random.randint(-10, 10) # 난수로 Y 좌표 결정
    bg.blit(imgBtlBG, [bx, by]) # (bx, by) 위치에 배경 표시
    if emy_blink % 2 == 0: # 적을 깜빡이기 위한 if 구문
        bg.blit(imgEnemy, [emy_x, emy_y + emy_step]) # 적 캐릭터 표시
    if emy_blink > 0: # 적을 깜빡이기 위한 변수가 설정되어 있다면
        emy_blink -= 1 # 해당 변수값 1 감소
    for i in range(10):
        draw_text(bg, message[i], 600, 100 + i * 50, fnt, WHITE) # 전투 메시지 표시

def battle_command(bg, fnt): # 전투 명령어 표시 함수
    for i in range(4):
        draw_text(bg, COMMAND[i], 20, 360 + 60 * i, fnt, WHITE) # 전투 명령어 표시

def main():
    global emy_step, emy_blink, dmg_eff
    idx = 10 # 게임 진행 관리 인덱스
    tmr = 0 # 게임 진행 관리 타이머 변수

    pygame.init()
    pygame.display.set_caption('Battle Turn')
    screen = pygame.display.set_mode((880, 720))
    clock = pygame.time.Clock()
    font = pygame.font.Font(None, 30)
    
    init_message()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
        
        draw_battle(screen, font)
        tmr += 1 # tmr 값 1 증가
        key = pygame.key.get_pressed()

        if idx == 10: # 전투 개시
            if tmr == 1: set_message('Encounter!') # tmr 값이 1이면 메시지 설정
            if tmr == 6: # tmr 값이 6이면 
                idx = 11 # 플레이어 입력 대기로 이동
                tmr = 0
        
        elif idx == 11: # 플레이어 입력 대기
            if tmr == 1: set_message('Your turn.')
            battle_command(screen, font) # 전투 명령어 표시
            if key[K_a] == 1 or key[K_SPACE] == 1: # [A]키 또는 [SPACE]키를 눌렀으면
                idx = 12 #  플레이어 공격으로 이동
                tmr = 0

        elif idx == 12: # 플레이어 공격
            if tmr == 1: set_message('You attack!')
            if 2 <= tmr and tmr <= 4: # tmr 값이 2에서 4 사이이면
                screen.blit(imgEffect, [700 - tmr * 120, -100 + tmr * 120]) #  공격 효과 표시
            if tmr == 5: # tmr 값이 5이면
                emy_blink = 5 # 적 깜빡임 효과 변수 설정
                set_message('***pts of damage!')
            if tmr == 16: # tmr 값이 16이면
                idx = 13 # 적 턴으로 이동
                tmr = 0
        
        elif idx == 13: # 적 턴, 적 공격
            if tmr == 1: set_message('Enemy turn.')
            if tmr == 5:
                set_message('Enemy attack!')
                emy_step = 30 # 적 이동 변수 설정
            if tmr == 9:
                set_message('***pts of damage!')
                dmg_eff = 5 # 화면 흔들림 변수 값 설정
                emy_step = 0 # 적을 원래 위치로 이동
            if tmr == 20:
                idx = 11 # 플레이어 입력 대기로 이동
                tmr = 0
        pygame.display.update()
        clock.tick(5)

if __name__ == '__main__':
    main()

이전에는 PyQt로 구현하느라 해보지 않았던 인덱스에 따른 구현을 해봤다.

화면 연출

# 게임 화면 연출
import pygame
import sys
import random

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

def main():
    pygame.init()
    pygame.display.set_caption('반투명과 스크롤')
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()

    surface_a = pygame.Surface((800, 600)) # 가로 800px, 세로 600px Surface 준비
    surface_a.fill(BLACK) # 해당 Surface를 검정색으로 채움
    surface_a.set_alpha(32) # 투명도 설정

    CHIP_MAX = 50 # 탄막 수
    cx = [0] * CHIP_MAX # 탄막 X 좌표
    cy = [0] * CHIP_MAX # 탄막 Y 좌표
    xp = [0] * CHIP_MAX # 탄막 X 방향 이동량
    yp = [0] * CHIP_MAX # 탄막 Y 방향 이동량
    for i in range(CHIP_MAX):
        cx[i] = random.randint(0, 800) # 난수로 탄막 x 좌표 결정
        cy[i] = random.randint(0, 600) # 난수로 탄막 y 좌표 결정
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
        
        screen.scroll(1, 4) # 화면에 그린 이미지 이동(스크롤)
        screen.blit(surface_a, [0, 0]) # 화면에 검은 반투명 Surface 겹침

        mx, my = pygame.mouse.get_pos() # 변수에 마우스 포인터 좌표 대입
        pygame.draw.rect(screen, WHITE, [mx - 4, my - 4, 8, 8]) # 마우스 포인터 좌표에 사각형 표시

        # 탄막의 이동량과 좌표 계산
        for i in range(CHIP_MAX): # 반복에서 탄막을 이동
            # 마우스 포인터 좌표와 탄막 좌표를 비교하고 X 방향과 Y 방향 이동량을 변경
            if mx < cx[i] and xp[i] > -20: xp[i] = xp[i] - 1
            if mx > cx[i] and xp[i] < 20: xp[i] = xp[i] + 1
            if my < cy[i] and yp[i] > -16: yp[i] = yp[i] - 1
            if my > cy[i] and yp[i] < 16: yp[i] = yp[i] + 1
            cx[i] = cx[i] + xp[i] # X 좌표 변경
            cy[i] = cy[i] + yp[i] # Y 좌표 변경
            pygame.draw.circle(screen, (0, 64, 192), [cx[i], cy[i]], 12) # 탄막 표시
            pygame.draw.circle(screen, (0, 128, 224), [cx[i], cy[i]], 9) # 탄막 표시
            pygame.draw.circle(screen, (192, 224, 244), [cx[i], cy[i]], 6) # 탄막 표시

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

if __name__ == '__main__':
    main()

탄막이 마우스 포인터를 쫓아가며 윈도우 안을 날아다닌다.

탄막은 좌표를 관리하는 cx, cy와 이동량을 관리하는 xp, yp 리스트를 사용해 관성의 영향을 받는 움직임으로 표시한다. 탄막의 이동량과 좌표를 계산할 때 좌표에 이동량을 더하는 것이 포인트이다.

반투명 Surface를 만드는데 set_alpha() 명령은 인수로 Surface 전체의 투명도를 지정한다. 인수값이 0이면 완전 투명, 255이면 완전 불투명이다.

scroll 명령은 윈도우 내에 그린 이미지를 스크롤한다. 인수는 이미지를 이동할 X 방향 픽셀 수, Y 방향 픽셀 수이다.

blit 명령으로 검은 반투명 Surface를 윈도우 전체에 겹쳤는데 이것을 통해 이전에 그려진 것들은 점점 반투명한 검은 막에 덮이다가 사라지는 것처럼 연출이 된다.