Pygame부터 JavaScript 배포까지, Gemini와 함께하는 AI 게임 개발 여정
다음 10가지 단계로 아이디어를 현실로 만듭니다. 프로젝트 설정부터 시작하여 Git/VS Code를 이용한 배포까지 다룹니다.
모든 작업은 하나의 프로젝트 폴더 안에서 이루어집니다. 이 폴더는 앞으로 만들 모든 코드와 파일을 담는 공간이 됩니다.
ai-game-project와 같이 프로젝트를 알아보기 쉬운 이름으로 새 폴더를 만듭니다.game_env.py, index.html 등)은 이 폴더 안에 저장됩니다.'추천 주제 보기' 버튼을 눌러 영감을 얻고, 마음에 드는 주제를 선택하여 상세 기획안을 요청하는 프롬프트를 복사하세요.
You are a creative game designer. Based on the theme "[여기에 선택한 게임 주제와 간단한 설명을 입력하세요. 예: 로켓 착륙시키기: 좌우 및 메인 추력을 사용해, 화면 상단에서 떨어지는 로켓이 정해진 착륙 지점에 부드럽게 착륙하는 게임]", please develop a detailed and engaging game plan.
The plan must be structured with the following four sections:
1. **Game Concept:** A brief, exciting one-paragraph summary of the game.
2. **Player Objective:** A clear description of what the player needs to accomplish.
3. **Controls:** A simple and intuitive control scheme.
4. **Win/Loss Conditions:** Specific, measurable conditions for success and failure.
Write the plan in Korean.
게임 기획안을 바탕으로 AI 학습과 사용자 플레이가 모두 가능한 통합 Python 파일을 제작합니다. 2단계 기획안을 아래에 붙여넣으면 프롬프트가 완성됩니다.
You are an expert Python developer specializing in both game development with Pygame and Reinforcement Learning with Gymnasium.
Your task is to create a single, complete Python script based on the provided game plan. This file must serve two purposes: be a playable game for humans when run directly, and be an importable, AI-trainable environment for RL agents.
### Game Logic Plan
[여기에 위 '게임 로직 기획' 입력란의 내용을 붙여넣으세요.]
### MANDATORY REQUIREMENTS:
1. **Single File Structure:** All code (Pygame logic, Gymnasium environment) must be in one single Python file.
2. **Standardized Naming (CRITICAL):**
* The Gymnasium environment class **MUST** be named `GameEnv`. This ensures compatibility with subsequent training scripts.
3. **Dual-Mode Execution (CRITICAL):**
* The script must use an `if __name__ == "__main__":` block.
* When the script is run directly (`python your_file_name.py`), this block should execute a "human player" mode.
* This mode should instantiate `GameEnv(render_mode='human')` and run a game loop where a human can play using the keyboard, allowing for immediate testing of the game mechanics.
4. **Gymnasium `GameEnv` Class:**
* **Observation/Action Spaces:** Analyze the game logic to define the most effective `observation_space` (Box) and `action_space` (Discrete).
* **Reward Function:** Design a precise reward function that strongly incentivizes the desired agent behavior.
* **Core Methods:** Correctly implement `__init__`, `reset`, `step`, `render`, and `close`.
* **No Physics Libraries:** Implement all physics from scratch (position, velocity, gravity, collision) using pure Python.
5. **Visual Design (Hyper-Casual Aesthetic):**
* The game must be minimalist, clean, and visually satisfying with a bright, harmonious color palette.
* Use anti-aliased geometric shapes and smooth, "juicy" animations for feedback. The window size should be 800x600.
6. **Code Quality:**
* The code must be well-commented, follow Python best practices, and be fully runnable without errors.
Gemini가 생성한 코드를 game_env.py 라는 이름으로 저장하세요. 터미널에서 python game_env.py를 실행하여 사람 플레이 모드로 게임을 직접 테스트해볼 수 있습니다.
`game_env.py` 파일을 사용하여 강화학습 에이전트를 학습시킵니다. 아래 코드를 train.py 파일로 저장하고 실행하세요. 코드 수정이 필요 없습니다.
# train.py
import os, time
from stable_baselines3 import PPO
from stable_baselines3.common.callbacks import CheckpointCallback
from stable_baselines3.common.logger import configure
from stable_baselines3.common.vec_env import DummyVecEnv
from gymnasium import spaces
from game_env import GameEnv
TOTAL_TIMESTEPS = 1_000_000
CHECKPOINT_FREQ = 10_000
LOG_DIR = "sb3_logs"
CHECKPOINT_DIR = os.path.join(LOG_DIR, "checkpoints")
def find_latest_checkpoint():
if not os.path.exists(CHECKPOINT_DIR): return None
checkpoints = [f for f in os.listdir(CHECKPOINT_DIR) if f.startswith("rl_model_") and f.endswith(".zip")]
if not checkpoints: return None
latest_checkpoint = max(checkpoints, key=lambda f: int(f.split("_")[2].replace(".zip", "")))
return os.path.join(CHECKPOINT_DIR, latest_checkpoint)
def main():
os.makedirs(CHECKPOINT_DIR, exist_ok=True)
env = DummyVecEnv([lambda: GameEnv(render_mode=None)])
obs_space = env.observation_space
policy = "CnnPolicy" if isinstance(obs_space, spaces.Box) and len(obs_space.shape) == 3 else "MlpPolicy"
print(f"자동 선택된 정책: {policy}")
latest_checkpoint = find_latest_checkpoint()
if latest_checkpoint:
print(f"최신 체크포인트에서 학습을 재개합니다: {latest_checkpoint}")
model = PPO.load(latest_checkpoint, env=env)
log_name = os.path.basename(os.path.dirname(os.path.dirname(latest_checkpoint)))
run_path = os.path.join(LOG_DIR, log_name)
custom_logger = configure(run_path, ["stdout", "tensorboard"])
model.set_logger(custom_logger)
else:
print("새로운 학습을 시작합니다.")
log_name = f"PPO_{int(time.time())}"
run_path = os.path.join(LOG_DIR, log_name)
custom_logger = configure(run_path, ["stdout", "tensorboard"])
model = PPO(policy, env, verbose=1, tensorboard_log=None)
model.set_logger(custom_logger)
checkpoint_callback = CheckpointCallback(save_freq=CHECKPOINT_FREQ, save_path=CHECKPOINT_DIR, name_prefix="rl_model")
try:
model.learn(total_timesteps=TOTAL_TIMESTEPS, callback=checkpoint_callback, reset_num_timesteps=False)
model.save(os.path.join(LOG_DIR, "final_model.zip"))
print(f"학습 완료! 최종 모델이 {os.path.join(LOG_DIR, 'final_model.zip')}에 저장되었습니다.")
finally:
env.close()
if __name__ == '__main__': main()
학습된 에이전트의 성능을 시각적으로 확인합니다. 아래 코드를 test_model.py로 저장하고 실행하세요.
# test_model.py
from stable_baselines3 import PPO
from game_env import GameEnv
MODEL_PATH = "sb3_logs/final_model.zip"
NUM_EPISODES = 10
def main():
env = GameEnv(render_mode='human')
model = PPO.load(MODEL_PATH, env=env)
print(f"{MODEL_PATH} 모델 테스트 시작.")
for episode in range(1, NUM_EPISODES + 1):
obs, info = env.reset()
done, total_reward = False, 0
while not done:
action, _ = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, info = env.step(action)
total_reward += reward
done = terminated or truncated
print(f"에피소드 {episode}: 총 보상 = {total_reward:.2f}")
env.close()
print("테스트 완료.")
if __name__ == '__main__': main()
학습된 모델을 웹에서 사용 가능한 ONNX 형식으로 변환합니다. 아래 코드를 convert_onnx.py로 저장하고 실행하세요.
# convert_onnx.py
import torch, onnxruntime as ort, numpy as np
from stable_baselines3 import PPO
from game_env import GameEnv
MODEL_PATH = "sb3_logs/final_model.zip"
ONNX_PATH = "model.onnx"
class OnnxablePolicy(torch.nn.Module):
def __init__(self, policy): super().__init__(); self.policy = policy
def forward(self, observation): action, _ = self.policy.predict(observation, deterministic=True); return torch.from_numpy(action)
def main():
model = PPO.load(MODEL_PATH, device='cpu')
onnxable_model = OnnxablePolicy(model.policy)
env = GameEnv(render_mode=None)
dummy_input = torch.randn(1, *env.observation_space.shape)
env.close()
torch.onnx.export(onnxable_model, dummy_input, ONNX_PATH, opset_version=12, input_names=["observation"], output_names=["action"])
print(f"ONNX 변환 완료: {ONNX_PATH}")
print("\n--- ONNX 모델 검증 ---")
try:
ort_session = ort.InferenceSession(ONNX_PATH)
input_name, output_name = ort_session.get_inputs()[0].name, ort_session.get_outputs()[0].name
result = ort_session.run([output_name], {input_name: dummy_input.numpy().astype(np.float32)})
print(f"검증 성공! 입력 shape: {dummy_input.numpy().shape}, 출력 action: {result[0]}")
except Exception as e: print(f"검증 실패: {e}")
if __name__ == '__main__': main()
AI의 플레이를 볼 수 있는 웹 페이지를 만듭니다. `game_env.py`의 시각적 디자인을 재현하고 AI 모델을 실행합니다.
`game_env.py` 파일을 열어 `GameEnv` 클래스에 정의된 `observation_space`의 구조와 순서를 복사한 후, 아래 프롬프트의 `[ ]` 안에 정확히 붙여넣으세요.
You are a senior front-end developer and a top-tier digital artist, skilled in JavaScript, HTML5 Canvas, and AI model integration. Your task is to create a single, self-contained `index.html` file that is a visually stunning, minimalist web game powered by a local `model.onnx` file.
### Reference Information
* **Artistic Vision:** Replicate the artistic vision of the Python game: a clean, minimalist, and visually satisfying hyper-casual aesthetic.
* **Observation Space Structure:** [여기에 단계 3에서 Gemini가 정의한 관측 공간의 구조와 순서를 정확히 붙여넣으세요. (예: `[pos_x, pos_y, vel_x, vel_y, angle, ang_vel, dist_to_pad]`)]
### Requirements:
1. **Game Replication:** Recreate the game's core mechanics and visuals using HTML5 Canvas and plain JavaScript. Do not use a physics library. The logic must be consistent with the Python implementation's coordinate system.
2. **Visual Design:** Center the canvas. Replicate the sophisticated visual style: a bright, inviting color palette; simple, anti-aliased geometric shapes; and bouncy, satisfying animations for feedback, powered by `requestAnimationFrame`. Implement a clean loading indicator.
3. **AI Integration:** Include `onnxruntime-web` via CDN and asynchronously load the local `model.onnx`.
4. **State and Action Fidelity (CRITICAL):**
* The observation passed to the model MUST be a `Float32Array`.
* The ORDER of elements in the JS observation array MUST EXACTLY MATCH the Python environment's `observation_space`.
* The normalization method used in JS MUST BE IDENTICAL to the normalization logic in the Python `step()` function.
* The mapping of the model's output to a game action in JavaScript MUST PERFECTLY MIRROR the `action_space` definition in the Python environment.
웹 게임을 인터넷에 올리기 전, 내 컴퓨터에서 먼저 실행하여 문제가 없는지 확인합니다. 간단한 로컬 서버를 사용하면 `model.onnx` 같은 외부 파일을 정상적으로 불러올 수 있습니다.
VS Code의 터미널(보기 → 터미널)에서 아래 명령어를 실행합니다.
python -m http.server웹 브라우저에서 http://localhost:8000 으로 접속하여 AI 웹 게임이 정상 실행되는지 확인하세요.
이제 완성된 프로젝트를 VS Code에서 바로 GitHub에 올리고, GitHub Pages를 통해 전 세계에 배포합니다.
Git이 설치되어 있지 않다면 git-scm.com에서 다운로드하여 설치합니다. 설치 후, Git Bash나 VS Code 터미널을 열어 아래 명령어를 입력하여 사용자 정보를 설정합니다 (최초 한 번만 필요).
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
VS Code 왼쪽 하단의 사람 모양 아이콘(계정)을 클릭하고, 'GitHub으로 로그인(Sign in with GitHub)'을 선택하여 브라우저의 안내에 따라 계정을 연동합니다.
VS Code 왼쪽의 '소스 제어' 탭(가지 모양 아이콘)으로 이동하여 '리포지토리 초기화(Initialize Repository)' 버튼을 클릭합니다. 그 후, 상단의 메시지 입력란에 "Initial commit"과 같은 첫 커밋 메시지를 작성한 후 ✓ 커밋 버튼을 눌러 커밋합니다.
'소스 제어' 탭에 나타나는 '게시(Publish)' 버튼을 클릭합니다. VS Code가 GitHub에 저장소를 만드는 과정을 안내합니다. 저장소 이름을 정하고, 반드시 '공개(Public)' 저장소로 설정해야 GitHub Pages를 무료로 사용할 수 있습니다.
게시가 완료되면 GitHub 사이트에서 방금 생성한 저장소로 이동합니다. 'Settings' → 'Pages' 탭으로 이동하여 'Source'를 'Deploy from a branch'로, 브랜치를 'main' (또는 'master')으로 선택하고 'Save'를 클릭합니다.
잠시 후 페이지 상단에 녹색으로 게시 주소(https://<사용자명>.github.io/<저장소명>/)가 나타납니다. 이 주소로 접속하여 게임을 확인하고 전 세계와 공유하세요!
축하합니다! 이 가이드를 통해 아이디어 구체화, 파이썬 AI 개발, 그리고 최종 웹 배포까지의 전 과정을 완료하셨습니다.