사용자 도구

사이트 도구


wiki:it:dream_of_enc:frontend:game_logic

게임: 이앤씨의 꿈 퀴즈 어드벤처

이 문서는 p5.js와 Tone.js를 기반으로 제작된 '이앤씨의 꿈 퀴즈 어드벤처' 게임의 핵심 로직과 알고리즘을 설명합니다.

1. 게임 설계: 기본 설정 및 전역 변수

게임의 가장 기본적인 규칙과 상태를 관리하는 변수들을 정의하는 영역입니다. 이 변수들을 통해 게임의 난이도, 퀴즈 내용, 시각적 테마 등을 손쉽게 조정할 수 있습니다.

1.1. 캔버스 및 퀴즈 설정

게임의 기준 해상도와 한 판에 등장할 퀴즈의 종류 및 개수를 설정합니다.

// Game Settings
const BASE_WIDTH = 960;  // 기준 너비
const BASE_HEIGHT = 576; // 기준 높이
let scaleFactor = 1;       // 화면 크기에 따른 스케일 비율

// NEW: Question Selection Settings
const SELECTED_QUIZ_KEYWORD = null; // 특정 키워드의 퀴즈만 로드 (null이면 전체)
const NUMBER_OF_QUIZZES_TO_LOAD = 20; // 가져올 문제의 개수

1.2. 게임 상태 및 주요 변수

게임의 현재 상태(gameState)를 문자열로 관리하여, 상태에 따라 다른 로직과 화면을 보여줍니다. 플레이어, 퀴즈, 아이템 등 핵심 객체들은 배열로 관리됩니다.

// Game State and Variables
let gameState = "AUDIO_PROMPT"; // 게임의 현재 상태 (예: "START_SCREEN", "PLAYING", "GAME_OVER")
let player; // 플레이어 객체
let quizzes = [], particles = [], obstacles = []; // 각종 객체를 담을 배열
let highScore = 0; // 최고 점수
let feverModeActive = false; // 피버 모드 활성화 여부

1.3. 색상 및 시각 요소

게임에 사용되는 모든 색상을 미리 변수로 정의합니다. 이를 통해 낮/밤 테마 변경 시 lerpColor() 함수로 두 색상 사이를 부드럽게 전환하고, 일관된 디자인을 유지합니다.

// Color Definitions
let DAY_SKY_TOP, DAY_SKY_BOT, NIGHT_SKY_TOP, NIGHT_SKY_BOT;
let DAY_MOUNTAIN, NIGHT_MOUNTAIN, DAY_HILL, NIGHT_HILL, DAY_GROUND, NIGHT_GROUND;
// ... (이하 생략)

2. 게임의 생명주기: p5.js 핵심 함수

p5.js 프레임워크의 생명주기에 따라 게임을 준비하고, 실행하고, 상호작용하는 핵심 함수들입니다.

2.1. preload()

게임이 시작되기 전, 가장 먼저 실행되는 함수입니다. 용량이 큰 이미지나 폰트 등 외부 리소스를 미리 불러와 메모리에 올려두는 역할을 합니다. 이를 통해 게임 시작 시 로딩 지연을 방지합니다.

function preload() {
bgFarImage = loadImage('assets/background_far.png'); // 원경 이미지
bgGroundImage = loadImage('assets/background_ground.png');
// ...
startScreenBackgroundImage = loadImage('assets/background_start.gif');
}

2.2. setup()

preload()가 끝난 후, 게임 시작에 필요한 모든 초기 설정을 단 한 번 실행하는 함수입니다. 캔버스를 생성하고, 색상 변수를 초기화하며, 플레이어와 각종 효과음(SFX) 객체를 생성합니다.

function setup() {
let canvas = createCanvas(windowWidth, windowHeight);
canvas.parent('game-container');

// 최초 게임 크기 조절
resizeGame(); 

// 색상 변수 초기화
DAY_SKY_TOP = color(135, 206, 235);
// ...

// 효과음 신디사이저 생성 (Tone.js)
jumpSound = new Tone.Synth(...).toDestination();
// ...

// 게임 시작 상태로 초기화
resetGame();

}

2.3. draw()

setup()이 끝난 후, 게임이 실행되는 동안 1초에 약 60번씩 계속해서 호출되는 메인 루프입니다. 이 함수 안에서 모든 게임의 로직 업데이트와 화면 그리기가 반복적으로 이루어집니다.

function draw() {
// 1. 매 프레임 게임의 모든 로직(움직임, 충돌 등)을 먼저 계산
updateGame();

// 2. 계산된 최신 상태를 바탕으로 화면을 그림
push(); // 현재 좌표계 저장
scale(scaleFactor); // 전체 캔버스 스케일링
clear(); // 이전 프레임 지우기

// 현재 게임 상태(gameState)에 따라 적절한 화면을 그림
if (gameState === "START_SCREEN") {
    drawStartScreen();
} else if (gameState === "PLAYING") {
    // 인게임 화면 그리기
    drawBackground();
    player.draw();
    // ...
}
// ...
pop(); // 저장했던 좌표계 복원

}

3. 게임의 두뇌: 핵심 로직과 상태 관리

draw() 함수 내부에서 호출되는 updateGame() 함수와, 각 게임 상태를 처리하는 핸들러 함수들이 게임의 실제 동작을 제어합니다.

3.1. updateGame(): 게임 월드의 지휘자

매 프레임마다 게임의 모든 요소를 업데이트하는 총괄 함수입니다.

카메라 이동: 플레이어의 위치에 따라 카메라의 x좌표를 업데이트하여, 화면이 자연스럽게 따라가도록 합니다.

플레이어 업데이트: 사용자의 입력을 받아 플레이어의 움직임을 계산하고, 중력을 적용합니다.

상태별 로직 실행: 현재 gameState에 맞는 핸들러 함수(예: handlePlayingState)를 호출하여 해당 상태에 필요한 로직만 실행합니다.

3.2. handlePlayingState(): 인게임 로직

gameState가 “PLAYING”일 때 실행됩니다.

객체 생성: 정해진 시간 간격에 따라 새로운 퀴즈, 아이템, 장애물을 생성하여 배열에 추가합니다.

객체 업데이트: 화면에 있는 모든 퀴즈, 아이템, 장애물 객체의 update() 메소드를 호출하여 각자 움직이도록 합니다.

충돌 처리: 플레이어와 다른 객체들 간의 충돌을 검사하고, 충돌 시 체력 감소, 점수 획득, 퀴즈 화면 전환 등의 이벤트를 처리합니다.

게임 종료 판정: 플레이어의 체력이 0이 되거나, 모든 퀴즈를 맞혔을 경우 gameState를 “GAME_OVER” 또는 “GAME_CLEAR”로 변경합니다.

4. 게임의 구성 요소: 주요 클래스 정의

게임에 등장하는 플레이어, 퀴즈, 장애물 등 핵심 객체들의 설계도(클래스)입니다.

4.1. Player 클래스

플레이어의 위치, 체력, 점수 등 모든 상태와 행동(점프, 이동, 충돌 처리)을 정의합니다. update() 메소드에서 물리 법칙(중력)을 계산하고, draw() 메소드에서 현재 상태(걷기, 점프 등)에 맞는 애니메이션을 그립니다.

class Player {
constructor() {
this.pos = createVector(120, BASE_HEIGHT * 0.85); // 위치
this.vel = createVector(0, 0); // 속도
this.hp = 3;
this.score = 0;
// ...
}

handleInput() { /* 키보드 및 터치 입력 처리 */ }
update() { /* 중력 적용 및 위치 업데이트 */ }
draw() { /* 플레이어 캐릭터 그리기 */ }
collidesWith(other) { /* 다른 객체와의 충돌 판정 */ }

}

4.2. Quiz 클래스

퀴즈 몬스터의 생성, 움직임, 플레이어와의 상호작용을 정의합니다. 각 퀴즈 객체는 자신의 문제 인덱스(qIdx)와 답변 완료 여부(answered) 상태를 가집니다.

class Quiz {
constructor(qIdx, x, type = 0) {
this.qIdx = qIdx; // questions 배열의 인덱스
this.pos = createVector(x, ...);
this.velX = -QUIZ_SPEED;
this.answered = false; // 답변 완료 여부
// ...
}
// ...
}

4.3. Obstacle 클래스

바위, 함정, 레이저 등 각종 장애물의 종류와 행동을 정의합니다. constructor에서 type에 따라 다른 크기와 속도를 가지도록 설정됩니다.

class Obstacle {
constructor(x, type) {
this.type = type; // 'ground_rock', 'pit_trap' 등
this.pos = createVector(x, ...);
this.hit = false; // 플레이어와 충돌했는지 여부
// ...
}
// ...
}

5. 랭킹 시스템 (서버 연동)

게임이 끝난 후, 점수를 서버에 저장하고 명예의 전당을 불러오는 기능입니다.

5.1. saveRankingToServer()

fetch API를 사용하여, 플레이어의 닉네임과 점수, 클리어 시간 등의 정보를 백엔드 Flask 서버(https://api.dreamofenc.com/api/game/add_ranking)로 전송(POST)합니다.

async function saveRankingToServer(nickname, score, hearts, timeMillis) {
const newEntry = {
nickname: nickname,
score: score,
// ...
};
try {
const response = await fetch(https://api.dreamofenc.com/api/game/add_ranking, {
method: 'POST',
headers: { 'Content-Type': 'application/json', },
body: JSON.stringify(newEntry),
});
// ...
} catch (error) {
// ...
}
}

5.2. loadRankingsFromServer()

마찬가지로 fetch를 사용하여, 서버에서 전체 랭킹 데이터를 받아와 화면에 표시할 rankings 배열에 저장합니다.

async function loadRankingsFromServer() {
try {
const response = await fetch(https://api.dreamofenc.com/api/game/get_rankings);
const data = await response.json();
rankings = data;
sortRankings();
} catch (error) {
// 서버 연결 실패 시 로컬 저장소 사용
}
}
wiki/it/dream_of_enc/frontend/game_logic.txt · 마지막으로 수정됨: 저자 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki