PyRacing.zip
2.58MB

14. 레이싱 게임 만들기 1 - 클래스를 이용하여 다수의 자동차 만들기

 

 

레이싱 게임 만들기 1

 

 

- 클래스를 이용하여 다수의 자동차 만들기

 

이전 강좌를 통해 스크린을 만들고, 스크린안에서 이미지를 움직이는 방법을 살펴보았다.

이와 같은 방법을 응용하여 레이싱 게임을 만들어보자.

게임의 내용은 도로위를 달리는 플레이어가 다수의 다른 차량을 피해가며 점수를 올리는 게임이다.

 

스크린위에 레이싱카를 만드는 방법은 모두 동일하다. 하지만 플레이어 차는 1대이고, 다른 차들은 여러대가 되어야 한다.

플레이어카는 키보드로 조작이 가능해야 하며, 다른 차들은 일정한 속도로 도로 위를 움직여야 한다.

도로 위를 움직인다는 것은 복잡하게 생각하지 말고, 스크린 위에서 아래로 내려온다고 생각하면 된다.

 

따라서 자동차는 자신의 이미지와 크기, 위치 속성을 가지고 있어야 하고, 위치를 움직이거나 충돌을 감지하는 메서드등을 가지고 있으면 된다.

 

여러가지 속성을 가지고 있고, 메서드를 가지고 있는 오브젝트를 만들기 위해서는 클래스를 이용하면 된다.

 

 

강좌에 사용하는 Image와 Sound는 첨부파일을 다운받아 사용한다.

이미지는 cars, Sound는 sound 폴더에 저장되어 있으며, 파이썬 파일이 있는 곳에 압축을 풀어 놓는다.

 

 

 

1. 클래스 시작, 다수의 자동차 이미지 List로 저장하기

 

첨부되어 있는 파일을 보면 cars 폴더에 CarXX 파일이 40개 있다. Car 이미지를 List로 저장한다. 

 

다른 변수 설명 : 

DIRCARS : 이미지 폴더 위치

STAGE : 게임 스테이지 저장

CAR_COUNT = 5 : 생성할 자동차 수

CARS = []  : 자동차 오브젝트를 넣을 List

 

import sys
import pygame
import random

 

# 게임 화면 크기
WINDOW_WIDTH = 550
WINDOW_HEIGHT = 800

 

# 색상

GRAY = (150, 150, 150)

 

# 소스 디렉토리

DIRCARS = "cars/"

DIRSOUND = "sound/"

 

# 기본 변수

STAGE = 1

CAR_COUNT = 5

 

# 자동차 오브젝트를 저장할 List

CARS = []

 

class Car:
    car_image = ['Car01.png', 'Car02.png', 'Car03.png', 'Car04.png', 'Car05.png', \
                 'Car06.png', 'Car07.png', 'Car08.png', 'Car09.png', 'Car10.png', \
                 'Car11.png', 'Car12.png', 'Car13.png', 'Car14.png', 'Car15.png', \
                 'Car16.png', 'Car17.png', 'Car18.png', 'Car19.png', 'Car20.png', \
                 'Car21.png', 'Car22.png', 'Car23.png', 'Car24.png', 'Car25.png', \
                 'Car26.png', 'Car27.png', 'Car28.png', 'Car29.png', 'Car30.png', \
                 'Car31.png', 'Car32.png', 'Car33.png', 'Car34.png', 'Car35.png', \
                 'Car36.png', 'Car37.png', 'Car38.png', 'Car39.png', 'Car40.png' ]

 

 

 

2. Class의 초기 작업

 

클래스의 내부 attribute로 image, x, y, dx, dy, rect 를 설정한다.

 

image = 선택된 자동차 이미지

x = 자동차 x 좌표

y = 자동차 y 좌표

dx = x좌표 이동 값

dy = y좌표 이동 값

rect = 이미지의 전체 좌표

 

    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 = ""

 

 

 

3. 자동차 이미지 불러오기

 

1) 이미지를 불러온다.

2) 이미지의 정보를 rect에 저장한다.

3) 이미지의 크기를 조정한다. 

4) 조정된 이미지의 크기를 rect에 저장한다.

5) 자동차의 생성 위치를 Random으로 정한다.

6) 자동차의 속도를 Random으로 정한다.

    def load_car(self):
            # 상대방 자동차

            # 40개의 이미지중에서 랜덤으로 선택한다.
            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

 

            # 생성 위치 - 스크린 크기 안에서 랜덤으로 x 좌표 생성. y 좌표는 스크린 밖 위에 생성
            self.rect.x = random.randrange(0, WINDOW_WIDTH - self.rect.width)
            self.rect.y = random.randrange(-150, -50)


            # STAGE에 따른 속도 변화, STAGE가 높아짐에 따라 자동차의 속도도 빨라진다.

            # 다양한 속도차이를 위해 5 ~ speed 사이에세 랜덤으로 속도를 선택하게 한다.
            speed = STAGE + 5
            if speed > 15:
                speed = 15
            self.dy = random.randint(5, speed)

 

 

 

4. 자동차 이미지 그리기 및 움직임 제어

 

    # 자동차를 스크린에 그리기

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

 

    # x 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요

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

 

    # y 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요,

    # 다른 자동차가 자동으로 위에서 아래로 내려올 때 필요

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

 

 

 

5. 자동차 스크린 밖으로 나가지 못하게 하기

 

    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

 

 

 

6. 자동차 충돌 감지

 

자동차 충돌을 감지하려면, 두 개의 자동차가 필요하다.

따라서 생성된 자기 자신과 다른 차량의 rect를 비교해야 한다.

코드는 오브젝트 충돌 감지 - https://www.jbmpa.com/pygame/13 를 응용한다.

 

self : 자기자신

car : 상대방 자동차

distance : 이미지의 충돌 거리 조정 용도

    def check_collision(self, car, distance = 0):
        # 차량 충돌 감지
        # distance : 오른쪽, 왼쪽, 아래쪽, 위쪽 이미지의 간격 설정

        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

 

 

 

7. Class 전체 코드

 

# 게임 화면 크기
WINDOW_WIDTH = 550
WINDOW_HEIGHT = 800

 

# 색상

GRAY = (150, 150, 150)

 

# 소스 디렉토리

DIRCARS = "cars/"

DIRSOUND = "sound/"

 

# 기본 변수

STAGE = 1

CAR_COUNT = 5

 

CARS = []

 

class Car:
    car_image = ['Car01.png', 'Car02.png', 'Car03.png', 'Car04.png', 'Car05.png', \
                 'Car06.png', 'Car07.png', 'Car08.png', 'Car09.png', 'Car10.png', \
                 'Car11.png', 'Car12.png', 'Car13.png', 'Car14.png', 'Car15.png', \
                 'Car16.png', 'Car17.png', 'Car18.png', 'Car19.png', 'Car20.png', \
                 'Car21.png', 'Car22.png', 'Car23.png', 'Car24.png', 'Car25.png', \
                 'Car26.png', 'Car27.png', 'Car28.png', 'Car29.png', 'Car30.png', \
                 'Car31.png', 'Car32.png', 'Car33.png', 'Car34.png', 'Car35.png', \
                 'Car36.png', 'Car37.png', 'Car38.png', 'Car39.png', 'Car40.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):
            # 상대방 자동차

            # 40개의 이미지중에서 랜덤으로 선택한다.
            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

 

            # 생성 위치 - 스크린 크기 안에서 랜덤으로 x 좌표 생성. y 좌표는 스크린 밖 위에 생성
            self.rect.x = random.randrange(0, WINDOW_WIDTH - self.rect.width)
            self.rect.y = random.randrange(-150, -50)


            # STAGE에 따른 속도 변화, STAGE가 높아짐에 따라 자동차의 속도도 빨라진다.

            # 다양한 속도차이를 위해 5 ~ speed 사이에세 랜덤으로 속도를 선택하게 한다.
            speed = STAGE + 5
            if speed > 15:
                speed = 15
            self.dy = random.randint(5, speed)

 

    # 자동차를 스크린에 그리기

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

 

    # x 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요

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

 

    # y 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요,

    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

 

    # 차량 충돌 감지
    # distance : 오른쪽, 왼쪽, 아래쪽, 위쪽 이미지의 간격 설정

    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

 

 

 

8. main 함수를 만들어서 게임루프 생성

 

def main():
    global SCREEN, CAR_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT

 

    # pygame 초기화 및 스크린 생성

    pygame.init()
    SCREEN = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT),
                                     pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE)
    pygame.display.set_caption("Racing Car Game")
    # 투명 아이콘은 32 x 32 로 해야 적용 됨
    windowicon = pygame.image.load(DIRCARS + 'icon.png').convert_alpha()
    pygame.display.set_icon(windowicon)

 

    clock = pygame.time.Clock()

 

    # 설정한 수 만큼 자동차 오브젝트 생성하여 CARS 리스트에 넣기

    for i in range(CAR_COUNT):
        car = Car(0, 0, 0, 0)
        car.load_car()
        CARS.append(car)

 

    playing = True

    while playing:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                playing = False
                pygame.quit()
                sys.exit()

 

        # 배경색을 회색으로
        SCREEN.fill(GRAY)

 

        ''' 게임 코드 작성 '''

 

 

        ''' 게임 코드 끝 '''

        pygame.display.flip()

 

        # 초당 프레임 설정
        clock.tick(60)

        

 

 

 

9. 게임 루프안에 자동으로 자동차를 움직이는 코드 작성

 

생성한 CARS List를 for문으로 loop 돌면서 지속적으로 dy 값을 늘려준다. 즉 위에서 아래로 움직이게 한다.

또한 차량의 충돌을 감지하여, 충돌시 상화좌우로 조금씩 움직이게 만들어준다. 충돌후 튕기는 효과

 

        ''' 게임 코드 작성 '''

 

        # 다른 자동차들 도로위에 움직이기
        for i in range(CAR_COUNT):
            CARS[i].draw_car()
            CARS[i].rect.y += CARS[i].dy

 

            # 화면 아래로 내려가면 자동차를 다시 로드한다.
            # 로드시 자동차의 이미지가 랜덤으로 바뀌므로 새로운 자동차가 생긴 듯한 효과가 있다.

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

 

        # 상대 자동차들끼리 충돌 감지, 각 자동차들을 순서대로 서로 비교
        for i in range(CAR_COUNT):
            for j in range(i + 1, CAR_COUNT):
                # 충돌 후 서로 팅겨 나가게 함.
                if CARS[i].check_collision(CARS[j]):
                    # 왼쪽에 있는 차는 왼쪽으로 오른쪽 차는 오른쪽으로 튕김
                    if CARS[i].rect.x > CARS[j].rect.x:
                        CARS[i].rect.x += 4
                        CARS[j].rect.x -= 4
                    else:
                        CARS[i].rect.x -= 4
                        CARS[j].rect.x += 4

 

                    # 위쪽 차는 위로, 아래쪽차는 아래로 튕김
                    if CARS[i].rect.y > CARS[j].rect.y:
                        CARS[i].rect.y += CARS[i].dy
                        CARS[j].rect.y -= CARS[j].dy
                    else:
                        CARS[i].rect.y -= CARS[i].dy
                        CARS[j].rect.y += CARS[j].dy

 

        ''' 게임 코드 끝 '''

 

 

 

10. 클래스 코드 + 메인함수 전체 코드

 

import sys
import pygame
import random

 

# 게임 화면 크기
WINDOW_WIDTH = 550
WINDOW_HEIGHT = 800

 

# 색상
GRAY = (150, 150, 150)

 

# 소스 디렉토리

DIRCARS = "cars/"

DIRSOUND = "sound/"

 

# 기본 변수

STAGE = 1

CAR_COUNT = 5

 

# 자동차 오브젝트를 저장할 List

CARS = []

 

class Car:
    car_image = ['Car01.png', 'Car02.png', 'Car03.png', 'Car04.png', 'Car05.png', \
                 'Car06.png', 'Car07.png', 'Car08.png', 'Car09.png', 'Car10.png', \
                 'Car11.png', 'Car12.png', 'Car13.png', 'Car14.png', 'Car15.png', \
                 'Car16.png', 'Car17.png', 'Car18.png', 'Car19.png', 'Car20.png', \
                 'Car21.png', 'Car22.png', 'Car23.png', 'Car24.png', 'Car25.png', \
                 'Car26.png', 'Car27.png', 'Car28.png', 'Car29.png', 'Car30.png', \
                 'Car31.png', 'Car32.png', 'Car33.png', 'Car34.png', 'Car35.png', \
                 'Car36.png', 'Car37.png', 'Car38.png', 'Car39.png', 'Car40.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):
            # 상대방 자동차

            # 40개의 이미지중에서 랜덤으로 선택한다.
            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

 

            # 생성 위치 - 스크린 크기 안에서 랜덤으로 x 좌표 생성. y 좌표는 스크린 밖 위에 생성
            self.rect.x = random.randrange(0, WINDOW_WIDTH - self.rect.width)
            self.rect.y = random.randrange(-150, -50)


            # STAGE에 따른 속도 변화, STAGE가 높아짐에 따라 자동차의 속도도 빨라진다.

            # 다양한 속도차이를 위해 5 ~ speed 사이에세 랜덤으로 속도를 선택하게 한다.
            speed = STAGE + 5
            if speed > 15:
                speed = 15
            self.dy = random.randint(5, speed)

 

    # 자동차를 스크린에 그리기

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

 

    # x 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요

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

 

    # y 좌표 이동 - 플레이어 자동차의 움직임 제어할 때 필요,

    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

 

    # 차량 충돌 감지
    # distance : 오른쪽, 왼쪽, 아래쪽, 위쪽 이미지의 간격 설정

    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

 

def main():
    global SCREEN, CAR_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT

 

    # pygame 초기화 및 스크린 생성

    pygame.init()
    SCREEN = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT),
                                     pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE)
    pygame.display.set_caption("Racing Car Game")
    # 투명 아이콘은 32 x 32 로 해야 적용 됨
    windowicon = pygame.image.load(DIRCARS + 'icon.png').convert_alpha()
    pygame.display.set_icon(windowicon)

 

    clock = pygame.time.Clock()

 

    # 설정한 수 만큼 자동차 오브젝트 생성하여 CARS 리스트에 넣기

    for i in range(CAR_COUNT):
        car = Car(0, 0, 0, 0)
        car.load_car()
        CARS.append(car)

 

    playing = True

    while playing:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                playing = False
                pygame.quit()
                sys.exit()

 

        # 배경색을 회색으로
        SCREEN.fill(GRAY)

 

        ''' 게임 코드 작성 '''

 

        # 다른 자동차들 도로위에 움직이기
        for i in range(CAR_COUNT):
            CARS[i].draw_car()
            CARS[i].rect.y += CARS[i].dy

 

            # 화면 아래로 내려가면 자동차를 다시 로드한다.
            # 로드시 자동차의 이미지가 랜덤으로 바뀌므로 새로운 자동차가 생긴 듯한 효과가 있다.

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

 

        # 상대 자동차들끼리 충돌 감지, 각 자동차들을 순서대로 서로 비교
        for i in range(CAR_COUNT):
            for j in range(i + 1, CAR_COUNT):
                # 충돌 후 서로 팅겨 나가게 함.
                if CARS[i].check_collision(CARS[j]):
                    # 왼쪽에 있는 차는 왼쪽으로 오른쪽 차는 오른쪽으로 튕김
                    if CARS[i].rect.x > CARS[j].rect.x:
                        CARS[i].rect.x += 4
                        CARS[j].rect.x -= 4
                    else:
                        CARS[i].rect.x -= 4
                        CARS[j].rect.x += 4

 

                    # 위쪽 차는 위로, 아래쪽차는 아래로 튕김
                    if CARS[i].rect.y > CARS[j].rect.y:
                        CARS[i].rect.y += CARS[i].dy
                        CARS[j].rect.y -= CARS[j].dy
                    else:
                        CARS[i].rect.y -= CARS[i].dy
                        CARS[j].rect.y += CARS[j].dy

 

        ''' 게임 코드 끝 '''

 

        pygame.display.flip()

 

        # 초당 프레임 설정
        clock.tick(60)

 

if __name__ == '__main__':
    main()

 

 

 

실행 결과

 

 

 

+ Recent posts