| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> |
| <title>GBA.js Mobile</title> |
| <link rel="stylesheet" href="resources/main.css"> |
| <style> |
| |
| body, html { |
| background: #000; margin: 0; padding: 0; |
| width: 100%; height: 100%; overflow: hidden; position: fixed; |
| } |
| #screen { |
| display: block; margin: 0 auto; width: 100vw; height: auto; |
| image-rendering: pixelated; |
| } |
| |
| |
| #touch-controls { |
| position: fixed; bottom: 0; left: 0; width: 100%; height: 260px; |
| z-index: 1000; pointer-events: none; |
| } |
| .btn { |
| position: absolute; background: rgba(255, 255, 255, 0.15); |
| border: 2px solid rgba(255, 255, 255, 0.3); color: white; |
| display: flex; align-items: center; justify-content: center; |
| font-family: sans-serif; font-weight: bold; pointer-events: auto; |
| touch-action: none; -webkit-user-select: none; user-select: none; |
| } |
| .btn:active { background: rgba(255, 255, 255, 0.4); } |
| |
| |
| #up { bottom: 170px; left: 80px; width: 65px; height: 65px; border-radius: 10px; } |
| #down { bottom: 40px; left: 80px; width: 65px; height: 65px; border-radius: 10px; } |
| #left { bottom: 105px; left: 15px; width: 65px; height: 65px; border-radius: 10px; } |
| #right { bottom: 105px; left: 145px; width: 65px; height: 65px; border-radius: 10px; } |
| |
| |
| #btn-a { bottom: 120px; right: 20px; width: 90px; height: 90px; border-radius: 50%; background: rgba(255, 0, 0, 0.2); } |
| #btn-b { bottom: 80px; right: 120px; width: 90px; height: 90px; border-radius: 50%; background: rgba(255, 255, 0, 0.2); } |
| |
| |
| #btn-l { top: 0px; left: 10px; width: 100px; height: 45px; border-radius: 5px; } |
| #btn-r { top: 0px; right: 10px; width: 100px; height: 45px; border-radius: 5px; } |
| |
| |
| .menu-btn { bottom: 20px; width: 85px; height: 40px; border-radius: 5px; font-size: 11px; } |
| #start { left: 50%; margin-left: 5px; } |
| #select { left: 50%; margin-left: -90px; } |
| |
| #controls { position: relative; z-index: 1001; text-align: center; color: white; padding-top: 10px; } |
| .hidden { display: none; } |
| </style> |
|
|
| <script src="js/util.js"></script> |
| <script src="js/core.js"></script> |
| <script src="js/arm.js"></script> |
| <script src="js/thumb.js"></script> |
| <script src="js/mmu.js"></script> |
| <script src="js/io.js"></script> |
| <script src="js/audio.js"></script> |
| <script src="js/video.js"></script> |
| <script src="js/video/proxy.js"></script> |
| <script src="js/video/software.js"></script> |
| <script src="js/irq.js"></script> |
| <script src="js/keypad.js"></script> |
| <script src="js/sio.js"></script> |
| <script src="js/savedata.js"></script> |
| <script src="js/gpio.js"></script> |
| <script src="js/gba.js"></script> |
| <script src="resources/xhr.js"></script> |
|
|
| <script> |
| var gba; |
| try { |
| gba = new GameBoyAdvance(); |
| gba.keypad.eatInput = true; |
| } catch (e) { |
| console.log(e); |
| } |
| |
| window.onload = function() { |
| if (gba) { |
| var canvas = document.getElementById('screen'); |
| gba.setCanvas(canvas); |
| loadRom('resources/bios.bin', function(bios) { |
| gba.setBios(bios); |
| }); |
| bindTouchGamepad(); |
| } |
| } |
| |
| function bindTouchGamepad() { |
| |
| const gbaKeys = { |
| 'btn-a': 0, 'btn-b': 1, 'select': 2, 'start': 3, |
| 'right': 4, 'left': 5, 'up': 6, 'down': 7, 'btn-r': 8, 'btn-l': 9 |
| }; |
| |
| Object.keys(gbaKeys).forEach(id => { |
| const el = document.getElementById(id); |
| const keyCode = gbaKeys[id]; |
| |
| const handleStart = (e) => { |
| e.preventDefault(); |
| |
| if (gba.audio.context && gba.audio.context.state === 'suspended') { |
| gba.audio.context.resume(); |
| } |
| gba.keypad.keydown(keyCode); |
| }; |
| |
| const handleEnd = (e) => { |
| e.preventDefault(); |
| gba.keypad.keyup(keyCode); |
| }; |
| |
| el.addEventListener('touchstart', handleStart, { passive: false }); |
| el.addEventListener('touchend', handleEnd, { passive: false }); |
| }); |
| } |
| |
| function run(file) { |
| gba.loadRomFromFile(file, function(result) { |
| if (result) { |
| document.getElementById('preload').style.display = 'none'; |
| document.getElementById('ingame').classList.remove('hidden'); |
| gba.runStable(); |
| } |
| }); |
| } |
| </script> |
| </head> |
| <body> |
|
|
| <canvas id="screen" width="480" height="320"></canvas> |
|
|
| <div id="touch-controls"> |
| <div class="btn" id="up">UP</div> |
| <div class="btn" id="down">DOWN</div> |
| <div class="btn" id="left">LEFT</div> |
| <div class="btn" id="right">RIGHT</div> |
| <div class="btn" id="btn-a">A</div> |
| <div class="btn" id="btn-b">B</div> |
| <div class="btn" id="btn-l">L</div> |
| <div class="btn" id="btn-r">R</div> |
| <div class="btn menu-btn" id="select">SELECT</div> |
| <div class="btn menu-btn" id="start">START</div> |
| </div> |
|
|
| <section id="controls"> |
| <div id="preload"> |
| <button onclick="document.getElementById('loader').click()" style="padding: 10px 20px;">LOAD ROM</button> |
| <input id="loader" type="file" accept=".gba" onchange="run(this.files[0]);" style="display:none;"> |
| </div> |
| <div id="ingame" class="hidden"> |
| <button onclick="gba.pause()">PAUSE</button> |
| <button onclick="gba.reset(); gba.runStable();">RESET</button> |
| </div> |
| </section> |
|
|
| </body> |
| </html> |
|
|