mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 00:01:34 +11:00
a start of a wrapper around mgba
This commit is contained in:
parent
ef1af49a5a
commit
7098e6937b
BIN
website/public/game.gba
Executable file
BIN
website/public/game.gba
Executable file
Binary file not shown.
|
@ -1,24 +1,18 @@
|
|||
import React from 'react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
import React, { useState } from 'react';
|
||||
import { Mgba } from './mgba';
|
||||
|
||||
function App() {
|
||||
|
||||
const [onGame, setOnGame] = useState(false);
|
||||
const [volume, setVolume] = useState(1.0);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
<div>
|
||||
{
|
||||
onGame && <><Mgba gameUrl="/game.gba" volume={volume} />
|
||||
<input type="range" value={volume} min="0" max="1" step="0.05" onChange={(e) => setVolume(Number(e.target.value))}></input></>
|
||||
}
|
||||
<button onClick={() => setOnGame(!onGame)}>{onGame ? "End Game" : "Start Game"}</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
|
@ -12,8 +10,3 @@ root.render(
|
|||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
|
|
97
website/src/mgba.tsx
Normal file
97
website/src/mgba.tsx
Normal file
|
@ -0,0 +1,97 @@
|
|||
import { FC, useEffect, useRef, useState } from "react";
|
||||
import mGBA from "./vendor/mgba";
|
||||
|
||||
type Module = any;
|
||||
|
||||
interface MgbaProps {
|
||||
gameUrl: string,
|
||||
volume?: Number,
|
||||
}
|
||||
|
||||
enum MgbaState {
|
||||
Uninitialised,
|
||||
Initialising,
|
||||
Initialised,
|
||||
}
|
||||
|
||||
const MGBA_ROM_DIRECTORY = "/data/games";
|
||||
|
||||
|
||||
export const Mgba: FC<MgbaProps> = ({ gameUrl, volume }) => {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const mgbaModule = useRef<Module>({});
|
||||
|
||||
const [state, setState] = useState(MgbaState.Uninitialised);
|
||||
|
||||
useEffect(() => {
|
||||
if (state !== MgbaState.Initialised) return;
|
||||
(async () => {
|
||||
const game = await fetch(gameUrl);
|
||||
const gameData = await game.arrayBuffer();
|
||||
|
||||
const gamePath = `${MGBA_ROM_DIRECTORY}/${gameUrl}`;
|
||||
mgbaModule.current.FS.writeFile(gamePath, new Uint8Array(gameData));
|
||||
mgbaModule.current.loadGame(gamePath);
|
||||
})()
|
||||
}, [state, gameUrl]);
|
||||
|
||||
// init mgba
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
|
||||
if (canvas === null) return;
|
||||
if (state !== MgbaState.Uninitialised) return;
|
||||
|
||||
setState(MgbaState.Initialising);
|
||||
|
||||
mgbaModule.current = {
|
||||
canvas: canvas.current,
|
||||
locateFile: (file: string) => {
|
||||
if (file === "mgba.wasm") {
|
||||
return "/vendor/mgba.wasm";
|
||||
}
|
||||
return file;
|
||||
}
|
||||
};
|
||||
|
||||
mGBA(mgbaModule.current).then((module: Module) => {
|
||||
mgbaModule.current = module;
|
||||
module.FSInit();
|
||||
setState(MgbaState.Initialised);
|
||||
});
|
||||
}
|
||||
)();
|
||||
|
||||
if (state === MgbaState.Initialised)
|
||||
return () => {
|
||||
try {
|
||||
mgbaModule.current.quitGame();
|
||||
mgbaModule.current.quitMgba();
|
||||
} catch { }
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
useEffect(() => {
|
||||
if (state !== MgbaState.Initialised) return;
|
||||
mgbaModule.current.setVolume(volume ?? 1.0);
|
||||
}, [state, volume]);
|
||||
|
||||
return <>
|
||||
|
||||
<canvas ref={canvas}></canvas>
|
||||
<button onClick={() => {
|
||||
if (state !== MgbaState.Initialised) return;
|
||||
mgbaModule.current.saveState(0);
|
||||
}}>Save State</button>
|
||||
<button onClick={() => {
|
||||
if (state !== MgbaState.Initialised) return;
|
||||
mgbaModule.current.loadState(0);
|
||||
}}>Load State</button>
|
||||
<button onClick={() => {
|
||||
if (state !== MgbaState.Initialised) return;
|
||||
mgbaModule.current.quickReload(0);
|
||||
}}>Restart</button>
|
||||
|
||||
</>;
|
||||
};
|
Loading…
Reference in a new issue