/** * Moth Game Framework * Higher-level game development framework built on top of Prosperon */ // Check if we received the required delay function if (!arg || arg.length === 0 || typeof arg[0] !== 'function') { throw new Error("moth module requires $_.delay function as first argument. Usage: use('moth', $_.delay)"); } // Verify it's actually a delay function by checking if it has the expected behavior var delay = arg[0]; if (!delay.name || (delay.name !== 'delay' && !delay.name.includes('delay'))) { console.warn("Warning: The function passed to moth module may not be $_.delay"); } var os = use('os'); var io = use('io'); var render = use('render'); var actor = use('actor'); var transform = use('transform'); var gameConfig = {}; var gameDir = ""; // Framework initialization function initialize() { var configPath = `config.js`; if (io.exists(configPath)) gameConfig = use(configPath); // Set up default config values gameConfig.resolution = gameConfig.resolution || { width: 640, height: 480 }; gameConfig.internal_resolution = gameConfig.internal_resolution || gameConfig.resolution; gameConfig.title = gameConfig.title || "Moth Game"; gameConfig.fps = gameConfig.fps || 60; gameConfig.clearColor = gameConfig.clearColor || [0, 0, 0, 1]; // Initialize render system render.initialize({ width: gameConfig.resolution.width, height: gameConfig.resolution.height, resolution_x: gameConfig.internal_resolution.width, resolution_y: gameConfig.internal_resolution.height, mode: gameConfig.mode || 'letterbox' }); // Set up default camera gameConfig.camera = gameConfig.camera || { size: [gameConfig.internal_resolution.width, gameConfig.internal_resolution.height], transform: new transform, fov: 50, near_z: 0, far_z: 1000, surface: undefined, viewport: {x: 0, y: 0, width: 1, height: 1}, ortho: true, anchor: [0, 0] }; // Set window title prosperon.window.title = gameConfig.title; startGameLoop(); } // Main game loop function startGameLoop() { var last = os.now(); var fpsTimer = 0; var fpsCount = 0; var targetFrameTime = 1 / gameConfig.fps; function loop() { var now = os.now(); var dt = now - last; last = now; // Dispatch update event prosperon.dispatch('update', dt); // Clear and set up rendering render.clear(gameConfig.clearColor); render.camera(gameConfig.camera); // Dispatch draw event prosperon.dispatch('draw'); // Present the frame render.present(); // FPS counter fpsTimer += dt; fpsCount++; if (fpsTimer >= 0.5) { // Only update if the title wasn't changed by the game if (prosperon.window.title === gameConfig.title) { prosperon.window.title = `${gameConfig.title} - FPS ${(fpsCount / fpsTimer).toFixed(1)}`; } fpsTimer = fpsCount = 0; } // Schedule next frame delay(loop, Math.max(0, targetFrameTime - (os.now() - now))); } loop(); } // Public API return { initialize: initialize, config: gameConfig };