티스토리 뷰

반응형

 

 

✍️ 이 튜토리얼은 ChatGPT를 활용해 Pygame 게임을 직접 만들고, 이를 웹과 앱으로 배포하는 전 과정을 실시간으로 구성해보는 과정을 담고 있습니다.
GPT에게 질문하고, 받은 코드와 설명을 바탕으로 실제로 게임을 만들고 배포해나가는 흐름 자체가 이 글의 핵심입니다.
AI를 활용해 하나의 게임이 어떻게 완성되고 앱으로 확장될 수 있는지를 그대로 따라가며 보여주는 실전형 튜토리얼입니다.

 

 

이 시간에는 Pygame으로 만든 Python 게임을 Flutter 기반 앱으로 배포하기 위한 준비 과정 중 1단계를 먼저 설명합니다.
먼저 pygbag을 활용해 Pygame 게임을 HTML/JS 형태로 변환하고, FastAPI로 정적 서버를 띄워 외부에서도 접속 가능한 웹 게임 형태로 만드는 방법을 정리했습니다.

왜 앱을 만들기 전에 먼저 웹으로 변환했을까요?
그 이유는 Flutter의 webview_flutter 라이브러리를 이용하면 웹사이트를 앱 화면 안에 그대로 띄울 수 있기 때문입니다.
즉, 게임을 Flutter로 다시 구현할 필요 없이, 웹으로 만든 게임 주소만 연결하면 네이티브 앱처럼 실행되는 앱을 만들 수 있습니다.

2편에서는 이렇게 만든 웹 게임을 Flutter WebView로 감싸 실제 APK 앱으로 빌드하고, 앱 배포까지 이어지는 실전 과정을 다룰 예정입니다.

 

 

 

 

[챗GPT와 함께 게임 개발 및 웹앱 배포하기 Start!]


Q. GPT 질문내용

 

pygame으로 간단한 게임하나 만들거고 그걸 pygbag이용해서 웹에 띄울거야.

어떤게임이냐면

1) 위에서 장애물들이 내려옴(대충 빨간 원): 그거맞으면 체력 깎임

2) 체력 0되면 죽고 3초뒤에 다음스테이지로 넘어감

3) 스테이지 시작마다 우측 상단에 시간 0으로 초기화. 진행시간 텍스트로 표시하기

4) 체력포션도 가끔 내려옴(그건 초록색 원으로 표시) 체력포션 먹으면 체력 참 5) 좌측 상단에 현재 내 체력바 표시 위와같이 게임 만들어주고, 그걸 pc에서도 띄울수있고 웹에서도 띄울수있는 버젼으로 코드 만들어줘.

 


 

A. GPT 답변내용

 

아래는 너가 말한 기능이 전부 포함된 Pygame 기반의 장애물 피하기 게임 코드야. 이 코드는 PC에서 실행도 가능하고, pygbag으로 웹에 배포도 할 수 있도록 설계됐어.


✅ 주요 기능

  1. 빨간 원이 위에서 떨어지며 부딪히면 체력 감소
  2. 체력이 0이 되면 "죽음", 10초 뒤 다음 스테이지로 자동 이동
  3. 스테이지마다 우상단에 시간 표시
  4. 초록 원(포션)이 가끔 떨어지며 닿으면 체력 회복
  5. 좌상단에는 체력바 표시

🟩 main.py (PC/웹 겸용)

import pygame
import random
import sys
import time

pygame.init()

WIDTH, HEIGHT = 800, 600
FPS = 60

WHITE = (255, 255, 255)
RED = (200, 0, 0)
GREEN = (0, 200, 0)
BLACK = (0, 0, 0)
GRAY = (100, 100, 100)

PLAYER_SIZE = 50
OBSTACLE_RADIUS = 20
POTION_RADIUS = 15
MAX_HEALTH = 100

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Falling Game")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)

player = pygame.Rect(WIDTH // 2, HEIGHT - 70, PLAYER_SIZE, PLAYER_SIZE)
health = MAX_HEALTH
player_speed = 7
obstacles = []
potions = []
stage = 1
start_time = time.time()
dead_time = None

obstacle_spawn_chance = 0.05  # 장애물 생성 확률
obstacle_speed = 7  # 장애물 속도


def draw_health_bar():
    pygame.draw.rect(screen, GRAY, (20, 20, 200, 20))
    pygame.draw.rect(screen, GREEN, (20, 20, 200 * (health / MAX_HEALTH), 20))

def draw_timer():
    elapsed = int(time.time() - start_time)
    timer_text = font.render(f"Time: {elapsed}s", True, WHITE)
    screen.blit(timer_text, (WIDTH - 150, 20))

def reset_stage():
    global obstacles, potions, health, start_time, dead_time, player
    obstacles.clear()
    potions.clear()
    health = MAX_HEALTH
    start_time = time.time()
    dead_time = None
    player.x = WIDTH // 2

running = True
while running:
    dt = clock.tick(FPS) / 1000

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]: player.x -= player_speed
    if keys[pygame.K_RIGHT]: player.x += player_speed
    player.x = max(0, min(WIDTH - PLAYER_SIZE, player.x))

    if health > 0:
        # 장애물 생성
        for _ in range(3):  # 한 번에 여러 장애물 시도
            if random.random() < obstacle_spawn_chance:
                x = random.randint(0, WIDTH - OBSTACLE_RADIUS * 2)
                obstacles.append(pygame.Rect(x, 0, OBSTACLE_RADIUS * 2, OBSTACLE_RADIUS * 2))

        # 포션 생성
        if random.random() < 0.005:
            x = random.randint(0, WIDTH - POTION_RADIUS * 2)
            potions.append(pygame.Rect(x, 0, POTION_RADIUS * 2, POTION_RADIUS * 2))

        # 충돌 처리
        for obs in obstacles[:]:
            obs.y += obstacle_speed
            if obs.colliderect(player):
                health -= 10
                obstacles.remove(obs)
            elif obs.y > HEIGHT:
                obstacles.remove(obs)

        for pot in potions[:]:
            pot.y += 4
            if pot.colliderect(player):
                health = min(MAX_HEALTH, health + 20)
                potions.remove(pot)
            elif pot.y > HEIGHT:
                potions.remove(pot)

    else:
        if dead_time is None:
            dead_time = time.time()
        elif time.time() - dead_time > 3:
            stage += 1
            reset_stage()

    screen.fill(BLACK)
    pygame.draw.rect(screen, WHITE, player)
    for obs in obstacles:
        pygame.draw.circle(screen, RED, obs.center, OBSTACLE_RADIUS)
    for pot in potions:
        pygame.draw.circle(screen, GREEN, pot.center, POTION_RADIUS)
    draw_health_bar()
    draw_timer()

    if health <= 0:
        text = font.render("You Died. Next Stage Soon...", True, WHITE)
        screen.blit(text, (WIDTH // 2 - 150, HEIGHT // 2))

    pygame.display.flip()

pygame.quit()
sys.exit()

💻 PC에서 실행

python main.py

🌐 웹에 배포 (pygbag)

  1. .py 파일을 해당 폴더에 두고:
python -m pygbag main.py

   2. 위 코드 실행하면 동일 디렉토리에 build폴더 생기고 웹서버 뜸. 웹 브라우저에서 http://localhost:8000 접속

 

위 웹서버 끄고 다음에 다시 접속하고 싶을때 (build는 필요없고 이미 빌드된 폴더로 이동하여 웹서버만 띄우기)

  1. build/web 폴더로 이동 후 로컬 서버 실행:
python -m http.server 8000
  1. 웹 브라우저에서 http://localhost:8000 접속

🌍 외부에서 접속하려면?

  • FastAPI로 배포하려면 uvicorn으로 웹서버 열고,
  • pygbag에서 만든 build/web 폴더 안 파일들을 그대로 서빙하면 됨.
  • 외부 접속 허용은 --host 0.0.0.0, 포트포워딩 필요.

필요하면 FastAPI 버전의 웹 배포 템플릿도 만들어줄게.

 

 

 


 

1. 챗GPT가 만들어준 pygame라이브러리 이용 장애물 피하기 게임 코드부터 정상작동하는지부터 확인해보기

 

해당 main.py파일이 있는 디렉토리로 이동하여 데스크탑에서 먼저 실행합니다

 

 

해당 폴더에서 python main.py로 실행

 

pygame으로 만든 python파일 PC에서 실행한 화면

 

 

 

2. 정상작동 확인 후 해당 코드로 웹서버 띄운 후 웹 접속과정

 

 

main.py가 있는 폴더 내로 이동해서 (cd 해당폴더경로)

 

pygbag --build main.py

cd build/web

python -m http.server 8000

 

하면 웹서버가 성공적으로 뜬 것이고, 해당 main.py가있는 폴더 내에 build폴더가 아래와같이 만들어진것을 확인할 수 있습니다

 

 

 

2. 띄운 내부 웹서버(로컬) 페이지로 이동 후 게임 실행 잘 되는지 확인

 

웹페이지 띄우고http://localhost:8000로 접속

 

위와같이 해당 로컬호스트 웹페이지에서 게임이 잘 실행되면 내 웹서버에 로컬로는 웹빌드가 잘 됐다고 볼 수 있습니다

 

그러나 외부에서도 접속가능 하도록 0.0.0.0으로 띄우려면 fastapi의 도움이 필요합니다

따라서 gpt에 FastAPI 버전의 웹 배포 방법도 알려줘 라고 질문하였습니다

 

 


Q. GPT 질문내용

 

 FastAPI 버전의 웹 배포 방법도 알려줘

 


 

 

A. GPT 답변내용

 

pygbag으로 만든 Pygame 게임을 FastAPI로 웹에서 외부 접속 가능하게 배포하려면 다음 단계를 따르면 됩니다:


✅ 2. FastAPI로 정적 파일 서빙 서버 만들기

server.py

from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI()

# 웹게임 정적 파일 경로 연결
app.mount("/", StaticFiles(directory="build/web", html=True), name="web")

위 코드에서 "build/web" 경로는 전단계에서 pygbag으로 빌드된 폴더입니다.


✅ 3. 실행 (외부 접속 허용)

uvicorn server:app --host 0.0.0.0 --port 80
  • 외부 접속용이라면:
    • 포트포워딩: 공유기 설정에서 80 포트를 열어줘야 함
    • 또는 클라우드 서버(예: EC2) 에 배포

✅ 4. 접속 URL

  • 로컬에서는:
    http://localhost:80
  • 외부에서:
    http://<공인 IP>:80

 

위와같이 server.py를 main.py가 있는 디렉토리에 생성 후 uvicorn으로 웹을 띄웁니다

 

 

 

그리고 나의 외부아이피로 해당 웹페이지를 접속해보겠습니다.

 

 

 

 

내 외부 아이피 주소 검색
내 외부 아이피 주소로 접속 시 정상동작 캡쳐화면

 

 

이로서 웹사이트에 pygame으로 만든 게임을 띄우는 과정을 마무리지었습니다.

 

*참고) pygame을 pygbag라이브러리를 이용해 웹서버에 띄우려면 해당 게임코드가 들어있는 파이썬의 '파일명'이 중요합니다.

위와같이 게임 코드가 있는 코드 파일명은 main.py로 (pygbag으로 build할때 쓰는 파일)

또 위 pygbag명령어를 통해 만들어진 build폴더가 있을때, 2차로 fastapi를 이용해 외부접속 가능한 웹서버를 띄울때 필요한 fastapi용 코드파일명은 main을 제외한 다른파일명으로 만들어주셔야 합니다.

 

다음 시간에는 flutter로 웹앱을 만들어 해당 게임을 핸드폰 등에서 실행시킬 수 있게 앱으로 배포하는 방법을 알려드리겠습니다. ^^

반응형