import {
HTMLManager,
InputManager,
SceneManager,
RenderManager,
PhysicsManager,
DestroyManager,
LayerManager,
} from "/src/engine/module.js";
import makeForm from "/src/engine/form.js";
import { Timer, writeErrorMessageOnDocument } from "/src/engine/utils.js";
/**
* 게임 로직을 실행하고 물리효과를 적용시키며 화면에 렌더링하는 엔진이다.
*/
class Engine {
/**
* 입력 이벤트를 관리하는 객체다.
*
* @property {InputManager}
* @static
*/
static inputManager;
/**
* deltaTime을 관리하는 객체다.
*
* @property {Timer}
* @static
*/
static timer;
constructor() {}
/**
* 인자로 전달된 값을 이용해 엔진을 초기화한다.
*
* @param {object} [settings]
* @param {number} [settings.width]
* @param {number} [settings.height]
* @param {number} [settings.fps]
* @param {string} [settings.title]
* @param {string} [settings.faviconPath]
* @param {GameObject} [settings.scene]
*/
static init(settings) {
try {
// 페이지의 타이틀을 정한다.
HTMLManager.setTitle(settings.title);
// 페이지의 아이콘을 정한다.
HTMLManager.setFavicon(settings.faviconPath);
// InputManager를 초기화한다.
Engine.inputManager = new InputManager();
// fps를 타이머에 등록하여 fixedDeltaTime을 프레임에 맞게 변경한다.
Engine.timer = new Timer();
Engine.timer.setFps(settings.fps);
// canvas의 해상도를 변경한다.
RenderManager.changeResolution(settings.width, settings.height);
// 레이어 상태를 초기화한다.
LayerManager.initializePhysicsInteractionState();
// 씬을 불러온다.
// 씬의 모든 리소스가 로드되었을 때 엔진을 실행하는
// 콜백함수를 인자로 넘겨준다.
SceneManager.loadScene(settings.scene, () => {
const engine = new Engine();
setInterval(engine.run, 1000 * Engine.timer.fixedDeltaTime);
});
} catch (error) {
writeErrorMessageOnDocument(error);
}
}
/**
* form으로부터 전달된 값으로 엔진을 초기화한다.
*
* @param {object} options
* @param {string} options.thumbnailImagePath
* @param {string} options.title
* @param {GameObject} options.scene
*/
static async initWithForm(options) {
// 먼저 form을 생성한다.
await makeForm(options.thumbnailImagePath, (data) => {
Engine.init({
width: data.width,
height: data.height,
fps: data.fps,
title: options.title,
scene: options.scene,
});
});
}
/**
* 게임 파이프라인에 대해서는 이 게시글을 참고했다.
* https://developer.ibm.com/tutorials/wa-build2dphysicsengine/#physics-loop-step
*/
run() {
try {
// 이전 프레임와 현재 프레임의 시간차를 계산한다.
Engine.timer.update();
// 키의 상태를 업데이트한다.
Engine.inputManager.update();
// 게임 로직을 처리한다.
SceneManager.getCurrentScene().update(Engine.timer.deltaTime);
// 물리 효과를 적용한다.
while (Engine.timer.accumulatedTime > Engine.timer.fixedDeltaTime) {
PhysicsManager.update(
SceneManager.getCurrentScene(),
Engine.timer.fixedDeltaTime
);
Engine.timer.accumulatedTime -= Engine.timer.fixedDeltaTime;
}
// 물리효과를 적용하고 나서 모든 오브젝트의 matrix를 업데이트한다.
SceneManager.getCurrentScene().calculateMatrix();
// 모든 오브젝트를 canvas에 그린다.
RenderManager.render();
// 삭제되길 기다리는 오브젝트가 있다면 모두 삭제한다.
DestroyManager.destroyAll();
} catch (error) {
writeErrorMessageOnDocument(error);
}
}
}
export default Engine;