Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Failing after 1m30s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
114 lines
3.0 KiB
JavaScript
114 lines
3.0 KiB
JavaScript
/**
|
|
* 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
|
|
}; |