스네이크 게임

스네이크 게임 제작기 1

잡코신 2024. 3. 6. 18:00
728x90
반응형

스네이크 게임이란?

영어로는 Snake game, 일본어로도 ヘビゲーム(뱀 게임)라고 부르는 이 게임은

구글에 스네이크 게임이라고 검색하면 바로 플레이 할 수도 있는 대중적이고 간단한 게임이다.

구글의 스네이크 게임

1970년대에 처음 나온 오래된 게임 장르로 아직까지도 수많은 변종들이 나오고 있는 인기 장르이다. 매우 단순한 규칙이지만 깊게 파고들면 끝이 없다는 폐인게임의 룰을 충실하게 따르고 있다.

스네이크 게임의 여러가지 옵션

많은 변수와 게임이 있어 설정 버튼을 누르고 모드와 뱀 스킨등을 변경할 수도 있다.

 

스네이크 게임 룰

플레이어는 화면에 있는 뱀(처럼 생긴 길쭉한 막대)을 조작해서 상하좌우로 움직일 수 있다.

뱀이 화면 끝이나 장애물에 부딪히거나, 뱀 머리가 몸통에 닿으면 죽으면서 생명을 잃는다.

맵 여기저기에서 랜덤으로 사과(게임에 따라서 약간씩 달라지는데 일반적으로는 사과)가 생성되는데,

뱀을 조작해서 사과를 먹으면 점수를 얻고 몸통이 길어진다.

 

스네이크 게임 만들기

프로그래밍 언어인 파이썬을 이용해서 스네이크 게임 룰에 기반한 스네이크 게임을 만든다.

import pygame
import random

 

우선 필요한 라이브러리를 임포트 해줄 것이다.

지렁이 게임 판이 되어주고 작동 기능을 구현할 GUI모듈로 pygame을, 랜덤으로 사과를 배치할 때 필요하게 random 라이브러리를 임포트 해준다. 참고로 파이게임(Pygame)은 파이썬 개발자를 위한 게임엔진이다.

pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("스네이크 게임")

clock = pygame.time.Clock()

clock.tick(10)

pygame.quit()

pygame을 사용하는 법은 간단하다.

먼저 pygame.init()로 라이브러리를 초기화 해준다.

초기화하지 않아도 작동은 되지만 일부 기능이 갑자기 되지 않을 수도 있다.

pygame.display.set_mode((width, height), flags=0, depth=0, display=0) 함수는 게임 창의 크기를 설정하고 해당 창을 생성한다. 위 코드에선 screen라는 창을 screen_width 너비와 screen_height 높이로 생성한 것을 알 수 있다.

flags는 창을 설정하는 데 사용되는 특별한 옵션을 나타내는 비트 플래그다. 주로 창의 속성을 지정하는 데 사용되는데, 예를 들어 pygame.FULLSCREEN 플래그를 사용하면 전체 화면 모드로 게임 창을 열 수 있다.

depth는 화면의 비트 수, 일반적으로 0이다.

display: 특정 디스플레이를 선택하는 데 사용됩니다. 기본값은 0으로, 모니터가 하나면 건드리지 않아도 된다.

pygame.time.Clock() 함수는 게임 루프 내에서 프레임 속도를 조절하게 해준다.

Pygame에서 제공하는 시간 관리 클래스인 Clock의 인스턴스를 생성해서 tick이라는 함수로 프레임 속도를 조절한다.

pygame.display.set_caption() 함수를 이용해서 창의 제목을 설정할 수 있다.
pygame.quit() Pygame 라이브러리를 종료하고 초기 상태로 돌리는 함수로 사용하면 프로그램이 종료된다.

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

screen_width = 800
screen_height = 600
cell_size = 20

 

파이게임에 대해 알아봤는데 그전에 사용할 변수를 미리 정의해줘야 한다.

난 배경, 지렁이, 사과 색과 화면 사이즈를 정의했다.

 

기본적인 화면 세팅 끝났으니 이 화면에서 돌아다니는 지렁이를 만들어야 한다.

지렁이는 파이썬에서 클래스라는 문법을 이용해 구현할것인데

이를 살펴보기 전에 간단하게 파이썬 클래스에 대하여 설명하고 넘어가겠다.

class Car:
    def __init__(self, brand, model):
        self.brand = brand
        self.model = model

    def start_engine(self):
        print(f"The {self.brand} {self.model}'s engine is started.")
        
my_car = Car(brand="HYENDAI", model="Avante")

 

클래스는 데이터와 데이터를 처리하는 메서드(함수)를 묶어놓은 것으로, 객체를 생성하기 위한 설계 도면이다.

클래스는 속성(멤버 변수)과 메서드(멤버 함수)를 가질 수 있다.

__init__이라 불리는 특별한 메서드는 객체가 생성될 때 자동으로 호출되는데, 이를 생성자라고 한다.

객체의 초기화를 담당한다.

위, 예시 Car 클래스 코드를 보면 brandmodel이라는 속성과 start_engine이라는 메서드를 가지고 있다.

그리고 클래스를 기반으로 실제로 메모리에 할당된 것을 객체라고 부른다.

예시로, Car 클래스의 인스턴스로서 my_car라는 객체를 생성했다.

 

다시 스네이크 게임 코드로 돌아와서

class Snake:
    def __init__(self):
        self.segments = [(screen_width // 2, screen_height // 2)] # 초기 위치
        self.direction = random.choice(['up', 'down', 'left', 'right']) # 초기 방향

    def move(self):
        x, y = self.segments[0]
        if self.direction == 'up':
            y -= cell_size
        elif self.direction == 'down':
            y += cell_size
        elif self.direction == 'left':
            x -= cell_size
        elif self.direction == 'right':
            x += cell_size
        self.segments.insert(0, (x, y)) # 새로운 머리 추가
        self.segments.pop() # 꼬리 제거

    def change_direction(self, direction):
        if direction == 'up' and self.direction != 'down':
            self.direction = 'up'
        elif direction == 'down' and self.direction != 'up':
            self.direction = 'down'
        elif direction == 'left' and self.direction != 'right':
            self.direction = 'left'
        elif direction == 'right' and self.direction != 'left':
            self.direction = 'right'

    def draw(self, screen):
        for segment in self.segments:
            pygame.draw.rect(screen, GREEN, (segment[0], segment[1], cell_size, cell_size))

 

위 코드를 보면 스네이크 클래스임을 알 수 있다. 각 메서드에 대해 설명한다.

  • __init__: 클래스의 초기화 메서드다. 여기에서는 초기 지렁이의 위치를 화면 중앙으로 설정하고, 랜덤으로 초기 방향을 정한다.
  • move: 지렁이를 움직이는 메서드다. 현재 방향에 따라 지렁이의 머리를 이동시키고, self.segments.pop 함수로 지렁이가 무한으로 늘어나지 않게 자른다.
  • change_direction: 지렁이의 방향을 변경하는 메서드다. 현재 방향과 반대 방향으로는 바로 변경되지 않도록 설정하고, 주어진 방향으로 변경하게 한다.
  • draw: 지렁이를 화면에 그리는 메서드다. pygame.draw.rect 함수를 사용하여 각 지렁이 세그먼트를 사각형으로 화면에 그린다.

간단하게 플레이어가 선택한 방향으로 새로운 머리를 그리고 지난 머리를 자르는 식으로 이동하는 것 처럼 보이게 만든 것이다.

game_over = False

while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_over = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                snake.change_direction('up')
            elif event.key == pygame.K_DOWN:
                snake.change_direction('down')
            elif event.key == pygame.K_LEFT:
                snake.change_direction('left')
            elif event.key == pygame.K_RIGHT:
                snake.change_direction('right')

    snake.move()

이제 메인 부분을 만든다.

가장 위 while문은 game_over가 ture로 바뀔 때까지 작동시키게 하고

다음 for event in pygame.event.get(): 는 pygame에서 이벤트를 수신하는 방식이다.

예를 들어 사용자가 키를 입력하거나 마우스를 움직이거나 하는 이벤트들을 지속적으로 검사하는 '이벤트 루프'인 것이다.

또 그중 이벤트가 pygame.QUIT라면 게임을 종료 시킨다.

그것이 아닌 방향키라면 그에 대해 머리의 방향을 바꾸고 이동시키는 무한 반복문 코드가 된 것이다.

    if (snake.segments[0][0] < 0 or snake.segments[0][0] >= screen_width or
            snake.segments[0][1] < 0 or snake.segments[0][1] >= screen_height or
            snake.segments[0] in snake.segments[1:]):
        game_over = True

    screen.fill(BLACK)

    snake.draw(screen)

    pygame.display.flip()

또 와일문 안 쪽에 벽이나 꼬리에 닿는다면 죽는 코드도 추가한다.

현재 화면을 검은 색으로 칠하고 지렁이를 그리는 코드를 추가해 pygame.display.flip()로 화면에 그림을 표시한다.

 

스네이크 게임(ver.1) 플레이하기

import pygame
import random

# 색깔 상수 정의
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

# 게임 화면 크기 설정
screen_width = 800
screen_height = 600
cell_size = 20

# 지렁이 클래스 정의
class Snake:
    def __init__(self):
        self.segments = [
            (screen_width // 2, screen_height // 2),
            (screen_width // 2 - cell_size, screen_height // 2),
            (screen_width // 2 - 2 * cell_size, screen_height // 2)
        ]
        self.direction = random.choice(['up', 'down', 'left', 'right'])

    def move(self):
        x, y = self.segments[0]
        if self.direction == 'up':
            y -= cell_size
        elif self.direction == 'down':
            y += cell_size
        elif self.direction == 'left':
            x -= cell_size
        elif self.direction == 'right':
            x += cell_size
        self.segments.insert(0, (x, y))
        self.segments.pop()

    def change_direction(self, direction):
        if direction == 'up' and self.direction != 'down':
            self.direction = 'up'
        elif direction == 'down' and self.direction != 'up':
            self.direction = 'down'
        elif direction == 'left' and self.direction != 'right':
            self.direction = 'left'
        elif direction == 'right' and self.direction != 'left':
            self.direction = 'right'

    def draw(self, screen):
        for segment in self.segments:
            pygame.draw.rect(screen, GREEN, (segment[0], segment[1], cell_size, cell_size))

# 게임 초기화
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("지렁이 게임")

clock = pygame.time.Clock()

snake = Snake()

game_over = False

# 게임 루프
while not game_over:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_over = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                snake.change_direction('up')
            elif event.key == pygame.K_DOWN:
                snake.change_direction('down')
            elif event.key == pygame.K_LEFT:
                snake.change_direction('left')
            elif event.key == pygame.K_RIGHT:
                snake.change_direction('right')

    snake.move()

    if (snake.segments[0][0] < 0 or snake.segments[0][0] >= screen_width or
            snake.segments[0][1] < 0 or snake.segments[0][1] >= screen_height or
            snake.segments[0] in snake.segments[1:]):
        game_over = True

    screen.fill(BLACK)

    snake.draw(screen)

    pygame.display.flip()
    clock.tick(10)

pygame.quit()

최종 코드이다. 코드들을 합치고 초기 세그먼트를 3개로 늘렸다.

이제 플레이 해보자.

지렁이가 잘 움직이는 것을 확인할 수 있다.

 

Next

다음엔 사과를 먹으면 몸이 늘어나는 로직도 추가하겠다.

728x90
반응형

'스네이크 게임' 카테고리의 다른 글

스네이크 게임 제작기 4  (0) 2024.04.10
스네이크 게임 제작기 3  (0) 2024.03.20
스네이크 게임 제작기 2  (0) 2024.03.13