pygame


파이게임으로 게임 만들기

자동차 피하기 게임


목차

  1. module import
  2. 변수
  3. Car 클래스
  4. 필요 함수
  5. main함수

module import

import pygame
import random
import sys
  • pygame모듈을 이용하여 pygame을 만듭니다. pygame을 무조건 써야죠.
  • random모듈은 난수를 생성해주는 모듈입니다. 저희는 다른 자동차들이 랜덤으로 나와야 하기 때문에 무조건 써야하는 모듈입니다.
  • sys모듈 : 인터프리터 제어

변수

WINDOW_WIDTH = 550
WINDOW_HEIGHT = 800
  • 게임 화면을 설정해줍니다. 여기선 가로 550, 세로 800으로 설정했습니다.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (150, 150, 150)
  • 이 게임에서 사용할 색상 정보를 나타냅니다.
DIRCARS = "cars/"
DIRSOUND = "sound/"

  • 소스 디렉토리를 나타냅니다.
STAGE = 1
CAR_COUNT = 5
SCORE = 0
STAGESCORE = 0

PNUMBER = 5
  • 기본적으로 설정해주는 변수들입니다.
    • 저희는 1라운드부터 진행하니 STAGE를 1로 설정했습니다.
    • CAR_COUNT는 플레이어의 목숨을 표시해주기 위해 쓰는 변수입니다.
    • SCORE는 점수입니다. 0부터 시작해야하니 0으로 초기화를 했습니다.
    • PNUMBER는 플레이어의 목숨 입니다

Car클래스

class Car:
    car_image = [
        'RacingCar01.png', 'RacingCar02.png', 'RacingCar03.png', 'RacingCar04.png', 'RacingCar05.png',
        'RacingCar06.png', 'RacingCar07.png', 'RacingCar08.png', 'RacingCar09.png', 'RacingCar10.png',
        'RacingCar11.png', 'RacingCar12.png', 'RacingCar13.png', 'RacingCar14.png', 'RacingCar15.png',
        'RacingCar16.png', 'RacingCar17.png', 'RacingCar18.png', 'RacingCar19.png', 'RacingCar20.png',
    ]

    def __init__(self, x=0, y=0, dx=0, dy=0):
        self.image = ""
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.rect = ""

    def load_car(self, p=""):
        if p == "p":
            self.image = pygame.image.load(DIRCARS + "RacingCar01.png")
            self.image = pygame.transform.scale(self.image, (40, 102))
            self.rect = self.image.get_rect()
            self.rect.x = self.x
            self.rect.y = self.y
        else:
            self.image = pygame.image.load(DIRCARS + random.choice(self.car_image))
            self.rect = self.image.get_rect()

            if self.rect.width <= 55:
                carwidth = self.rect.width - 15
                carheight = round((self.rect.height * carwidth) / self.rect.width)
            else:
                carwidth = self.rect.width
                carheight = self.rect.height

            self.image = pygame.transform.scale(self.image, (carwidth, carheight))
            self.rect.width = carwidth
            self.rect.height = carheight

            self.rect.x = random.randrange(0, WINDOW_WIDTH - self.rect.width)
            self.rect.y = random.randrange(-150, -50)

            speed = (STAGE*2) + 6
            if speed > 50:
                speed = 50
            self.dy = random.randint(8, speed)

    def draw_car(self):
        SCREEN.blit(self.image, [self.rect.x, self.rect.y])

    def move_x(self):
        self.rect.x += self.dx

    def move_y(self):
        self.rect.y += self.dy

    def check_screen(self):
        if self.rect.right > WINDOW_WIDTH or self.rect.x < 0:
            self.rect.x -= self.dx
        if self.rect.bottom > WINDOW_HEIGHT or self.rect.y < 0:
            self.rect.y -= self.dy

    def check_collision(self, car, distance=0):
        if (
            self.rect.top + distance < car.rect.bottom
            and car.rect.top < self.rect.bottom - distance
            and self.rect.left + distance < car.rect.right
            and car.rect.left < self.rect.right - distance
        ):
            return True
        else:
            return False
  • 자동차를 불러오는 것과 자동차 동작들에 관한 클래스 입니다.
  • 자동차에 관한 모든 함수가 있다고 생각하면 됩니다.
  • load_car함수는 저 위의 자동차 이미지를 게임에 불러오는 겁니다.

필요 함수

def draw_score():
    font_01 = pygame.font.SysFont("FixedSsy", 30, True, False)
    text_score = font_01.render("Score : " + str(SCORE), True, BLACK)
    SCREEN.blit(text_score, [15, 15])

    text_stage = font_01.render("STAGE : " + str(STAGE), True, BLACK)
    text_stage_rect = text_stage.get_rect()
    text_stage_rect.centerx = round(WINDOW_WIDTH / 2)
    SCREEN.blit(text_stage, [text_stage_rect.x, 15])

    for i in range(PNUMBER):
        if i < 5:
            pimage = pygame.image.load(DIRCARS + 'RacingCar01.png')
            pimage = pygame.transform.scale(pimage, (15, 38))
            px = WINDOW_WIDTH - 20 - (i * 30)
            SCREEN.blit(pimage, [px, 15])
        else:
            text_pnumber = font_01.render("+" + str(PNUMBER - 5), True, WHITE)
            text_pnumber_x = WINDOW_WIDTH - 30 - (5 * 30)
            SCREEN.blit(text_pnumber, [text_pnumber_x, 25])


def increase_score():
    global SCORE, STAGE, STAGESCORE

    SCORE += 10 + STAGE - 1

    if SCORE >= STAGESCORE + 1000:
        STAGE += 1
        STAGESCORE += 1000
        
        # 3스테이지마다 CAR_COUNT를 2 증가
        if STAGE % 3 == 0:
            #최대 20대 까지만 증가하게
            global CAR_COUNT
            CAR_COUNT = min(CAR_COUNT + 2, 20)
            
            for _ in range(CAR_COUNT - len(CARS)):
                car = Car(0, 0, 0, 0)
                car.load_car()
                CARS.append(car)


def show_start_screen():
    global SCORE, STAGE, STAGESCORE, PNUMBER, CARS

    SCORE = 0
    STAGE = 1
    STAGESCORE = 0
    PNUMBER = 5
    CARS = []

    start_screen = True
    while start_screen:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    start_screen = False

        SCREEN.fill(WHITE)

        font = pygame.font.SysFont("FixedSsy", 50, True, False)
        text = font.render("Press Enter to Start", True, BLACK)
        text_rect = text.get_rect(center=(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2))
        SCREEN.blit(text, text_rect)

        pygame.display.flip()


def show_end_screen():
    global SCORE, STAGE, STAGESCORE, PNUMBER, CARS

    end_screen = True
    while end_screen:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    end_screen = False
                elif event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    sys.exit()
                elif event.key == pygame.K_r:
                    return True
                  
        SCREEN.fill(WHITE)

        font = pygame.font.SysFont("FixedSsy", 50, True, False)
        text = font.render("Game Over", True, BLACK)
        text_rect = text.get_rect(center=(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 3))
        SCREEN.blit(text, text_rect)

        score_text = font.render("Final Score: " + str(SCORE), True, BLACK)
        score_rect = score_text.get_rect(center=(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2))
        SCREEN.blit(score_text, score_rect)

        restart_text = font.render("Press R to Restart", True, BLACK)
        restart_rect = restart_text.get_rect(center=(WINDOW_WIDTH / 2, 2 * WINDOW_HEIGHT / 3))
        SCREEN.blit(restart_text, restart_rect)

        exit_text = font.render("Press ESC to Exit", True, BLACK)
        exit_rect = exit_text.get_rect(center=(WINDOW_WIDTH / 2, 5 * WINDOW_HEIGHT / 6))
        SCREEN.blit(exit_text, exit_rect)

        pygame.display.flip()

    return False
  • 게임 진행에 있어 필요한 함수들이다.
  • 점수 표시, 점수 올리기, 시작화면, 끝 화면을 구현한 함수들이다.
  • 종료화면의 경우 R을 누르면 다시시작 기능이 구현되어 있다.

### 메인함수

 def main():
    global SCREEN, CAR_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT, PNUMBER, SCORE, STAGE, STAGESCORE

    pygame.init()
    SCREEN = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE)
    pygame.display.set_caption("Racing Car Game")
    windowicon = pygame.image.load(DIRCARS + 'PyCar.png').convert_alpha()
    pygame.display.set_icon(windowicon)

    while True:
        show_start_screen()

        clock = pygame.time.Clock()
        pygame.mixer.music.load(DIRSOUND + 'background.ogg')
        sound_crash = pygame.mixer.Sound(DIRSOUND + 'crash.ogg')
        pygame.mixer.music.play(-1)

        player = Car(round(WINDOW_WIDTH / 2), round(WINDOW_HEIGHT - 150), 0, 0)
        player.load_car("p")
        
        for i in range(CAR_COUNT):
            car = Car(0, 0, 0, 0)
            car.load_car()
            CARS.append(car)

        playing = True
        while playing and PNUMBER > 0:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    playing = False
                    pygame.quit()
                    sys.exit()

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT:
                        player.dx = 5
                    elif event.key == pygame.K_LEFT:
                        player.dx = -5
                    if event.key == pygame.K_DOWN:
                        player.dy = 5
                    elif event.key == pygame.K_UP:
                        player.dy = -5
                    if event.key == pygame.K_ESCAPE:
                        return

                if event.type == pygame.KEYUP:
                    if event.key == pygame.K_RIGHT:
                        player.dx = 0
                    elif event.key == pygame.K_LEFT:
                        player.dx = 0
                    if event.key == pygame.K_DOWN:
                        player.dy = 0
                    elif event.key == pygame.K_UP:
                        player.dy = 0

            SCREEN.fill(GRAY)

            player.draw_car()
            player.move_x()
            player.move_y()
            player.check_screen()

            for i in range(CAR_COUNT):
                CARS[i].draw_car()
                CARS[i].rect.y += CARS[i].dy

                if CARS[i].rect.y > WINDOW_HEIGHT:
                    increase_score()
                    CARS[i].load_car()

            for i in range(CAR_COUNT):
                if player.check_collision(CARS[i], 5):
                    PNUMBER -= 1
                    sound_crash.play()

                    if player.rect.x > CARS[i].rect.x:
                        CARS[i].rect.x -= CARS[i].rect.width + 10
                    else:
                        CARS[i].rect.x += CARS[i].rect.width + 10

                    if player.rect.y > CARS[i].rect.y:
                        CARS[i].rect.y -= 30
                    else:
                        CARS[i].rect.y += 30

            draw_score()
            pygame.display.flip()
            clock.tick(60)

        if not show_end_screen():
            break

if __name__ == '__main__':
    main()
  • 게임을 실제로 진행시키는 메인함수입니다.
  • 앞에 나와있는 클래스나 함수들을 바탕으로 실제로 게임을 진행시키는 역할을 합니다.

여기까진 게임 코드 입니다. 혹시 실제로 플레이하고 싶으시면 avoid_car를 클론해서 해보시기 바랍니다.