66 lines
2.8 KiB
HTML
66 lines
2.8 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="en">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<title>Plugin System: Audio Example</title>
|
||
|
|
<style>
|
||
|
|
body { font-family: sans-serif; line-height: 1.6; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #333; }
|
||
|
|
code { background: #f4f4f4; padding: 2px 4px; border-radius: 4px; }
|
||
|
|
pre { background: #2d2d2d; color: #fff; padding: 15px; border-radius: 6px; overflow-x: auto; }
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<h1>Plugin Architecture: Audio System</h1>
|
||
|
|
<p>This guide demonstrates how to create a "pop-in" plugin that listens for game events and triggers audio, maintaining strict separation of concerns.</p>
|
||
|
|
|
||
|
|
<h2>1. The Design Principle</h2>
|
||
|
|
<p>The core engine does <strong>not</strong> contain a "play sound" function inside the combat logic. Instead, the combat logic emits an event. The Audio Plugin sits in the background, listening for that specific event, and plays the sound when it hears it.</p>
|
||
|
|
|
||
|
|
<h2>2. The Plugin Implementation</h2>
|
||
|
|
<pre><code>// plugins/AudioPlugin.js
|
||
|
|
export const AudioPlugin = {
|
||
|
|
id: 'audio-system',
|
||
|
|
|
||
|
|
// The engine calls this upon loading the plugin
|
||
|
|
init(eventBus, assetManager) {
|
||
|
|
this.eventBus = eventBus;
|
||
|
|
this.assetManager = assetManager;
|
||
|
|
|
||
|
|
// Listen for global game events
|
||
|
|
this.eventBus.on('ENTITY_DIED', (data) => {
|
||
|
|
this.playSound('explosion_01.mp3');
|
||
|
|
});
|
||
|
|
|
||
|
|
this.eventBus.on('PLAYER_JUMP', () => {
|
||
|
|
this.playSound('jump_sfx.ogg');
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
playSound(fileName) {
|
||
|
|
// Access pre-loaded audio buffers from the asset manager
|
||
|
|
const sound = this.assetManager.getAudio(fileName);
|
||
|
|
sound.play();
|
||
|
|
}
|
||
|
|
};</code></pre>
|
||
|
|
|
||
|
|
<h2>3. How it "Pops In"</h2>
|
||
|
|
<p>Because the plugin follows a standard interface (the <code>init</code> function), the core engine's loader handles it automatically:</p>
|
||
|
|
<pre><code>// Core Engine Loader
|
||
|
|
async function loadPlugins() {
|
||
|
|
const pluginFiles = ['plugins/AudioPlugin.js', 'plugins/RendererPlugin.js'];
|
||
|
|
|
||
|
|
for (const path of pluginFiles) {
|
||
|
|
const { plugin } = await import(path);
|
||
|
|
// Inject the Event Bus so the plugin can "talk" to the rest of the game
|
||
|
|
plugin.init(globalEventBus, globalAssetManager);
|
||
|
|
}
|
||
|
|
}</code></pre>
|
||
|
|
|
||
|
|
<h2>4. Key Benefits</h2>
|
||
|
|
<ul>
|
||
|
|
<li><strong>Zero Coupling:</strong> If you remove <code>AudioPlugin.js</code>, the combat system continues to function perfectly without errors.</li>
|
||
|
|
<li><strong>Easy Testing:</strong> You can test the audio system in isolation by manually firing an <code>ENTITY_DIED</code> event from the browser console.</li>
|
||
|
|
<li><strong>Performance:</strong> The audio plugin only reacts to events. It does not run in the main 60fps render loop, keeping the core engine lightweight.</li>
|
||
|
|
</ul>
|
||
|
|
</body>
|
||
|
|
</html>
|