lucky / index 20.html
Studytime171's picture
Duplicate from Studytime171/Lalitgangwani
89610f7
<!DOCTYPE html>
<html lang="en">
<head>
<meta 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 - Touch Enabled</title>
<!-- Keep your original CSS file if you have custom styles -->
<link rel="stylesheet" href="resources/main.css">
<!-- Inline styles for responsive touch controls + anti-zoom -->
<style>
* { margin:0; padding:0; box-sizing:border-box; }
html, body {
height:100%;
overflow:hidden;
background:#000;
touch-action: manipulation; /* Reduces double-tap zoom & tap delay */
font-family: sans-serif;
}
#screen-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: #111;
}
#screen {
width: 100%;
height: auto;
max-width: 100%;
max-height: 100%;
image-rendering: pixelated; /* Crisp pixels when scaled */
touch-action: none;
}
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 20;
color: white;
background: rgba(0,0,0,0.6);
padding: 10px;
border-radius: 8px;
display: none;
}
#controls.visible { display: block; }
.bigbutton {
padding: 10px 20px;
font-size: 16px;
margin: 5px;
}
#touchControls {
position: absolute;
inset: 0;
pointer-events: none;
display: none;
z-index: 10;
padding: 3vmin;
}
button {
font-weight: bold;
color: white;
border: none;
border-radius: 50%;
opacity: 0.65;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
user-select: none;
}
button:active { opacity: 0.95; }
#dpad {
display: grid;
grid-template-columns: repeat(3, 20vmin);
grid-template-rows: repeat(3, 20vmin);
gap: 1.5vmin;
}
#faceButtons {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 3vmin;
}
.shoulder {
width: 20vmin;
height: 12vmin;
border-radius: 12vmin;
background: rgba(220,220,220,0.6);
font-size: 4vmin;
}
.startselect {
width: 20vmin;
height: 12vmin;
border-radius: 10vmin;
background: rgba(0,200,0,0.6);
font-size: 3.5vmin;
}
#a { background: rgba(255,60,60,0.8); width: 24vmin; height: 24vmin; font-size: 6vmin; }
#b { background: rgba(60,60,255,0.8); width: 24vmin; height: 24vmin; font-size: 6vmin; }
/* Landscape adjustment */
@media (orientation: landscape) {
#touchControls {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
}
#dpad { grid-template-columns: repeat(3, 16vmin); grid-template-rows: repeat(3, 16vmin); }
#faceButtons { flex-direction: row; align-items: flex-end; gap: 5vmin; }
#faceButtons > div { flex-direction: column; }
}
/* Portrait adjustment */
@media (orientation: portrait) {
#touchControls {
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 4vmin;
}
#dpad { align-self: flex-start; }
#faceButtons { align-self: flex-end; }
}
</style>
<!-- All original GBA.js scripts -->
<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;
var runCommands = [];
var debug = null;
try {
gba = new GameBoyAdvance();
gba.keypad.eatInput = true;
gba.setLogger(function(level, error) {
console.log(error);
gba.pause();
var screen = document.getElementById('screen');
if (screen.className === 'dead') return;
var crash = document.createElement('img');
crash.id = 'crash';
crash.src = 'resources/crash.png';
screen.parentElement.insertBefore(crash, screen);
screen.className = 'dead';
});
} catch (e) {
gba = null;
}
window.onload = function() {
if (gba && FileReader) {
var canvas = document.getElementById('screen');
gba.setCanvas(canvas);
gba.logLevel = gba.LOG_ERROR;
loadRom('resources/bios.bin', function(bios) {
if (bios) gba.setBios(bios);
});
if (!gba.audio.context) {
var soundbox = document.getElementById('sound');
if (soundbox) soundbox.parentElement.removeChild(soundbox);
}
if (navigator.userAgent.indexOf('MSIE') !== -1 || !!document.documentMode) {
var pixelatedBox = document.getElementById('pixelated');
if (pixelatedBox) pixelatedBox.parentElement.removeChild(pixelatedBox);
}
// Show touch controls on touch devices
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
document.getElementById('touchControls').style.display = 'flex';
canvas.style.maxHeight = '75vh'; // Leave room for controls in portrait
}
setupTouchControls();
} else {
var ctrls = document.getElementById('controls');
if (ctrls) ctrls.parentElement.removeChild(ctrls);
}
};
function loadRom(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (xhr.status === 200) callback(new Uint8Array(xhr.response));
else callback(null);
};
xhr.send();
}
function fadeOut(id, nextId, kill) {
var e = document.getElementById(id);
var e2 = document.getElementById(nextId);
if (!e) return;
var removeSelf = function() {
if (kill) e.parentElement.removeChild(e);
else {
e.className = 'dead';
e.removeEventListener('transitionend', removeSelf);
}
if (e2) {
e2.className = 'hidden';
setTimeout(() => e2.className = '', 0);
}
};
e.addEventListener('transitionend', removeSelf);
e.className = 'hidden';
}
function run(file) {
document.getElementById('loader').value = '';
var loadBtn = document.getElementById('select');
loadBtn.textContent = 'Loading...';
loadBtn.removeAttribute('onclick');
document.getElementById('pause').textContent = "PAUSE";
gba.loadRomFromFile(file, function(result) {
if (result) {
runCommands.forEach(cmd => cmd());
runCommands = [];
fadeOut('preload', 'ingame');
fadeOut('instructions', null, true);
gba.runStable();
document.getElementById('controls').classList.add('visible');
} else {
loadBtn.textContent = 'FAILED';
setTimeout(() => {
loadBtn.textContent = 'SELECT';
loadBtn.onclick = () => document.getElementById('loader').click();
}, 3000);
}
});
}
function reset() {
gba.pause();
gba.reset();
document.getElementById('select').textContent = 'SELECT';
var crash = document.getElementById('crash');
if (crash) {
crash.parentElement.removeChild(crash);
document.getElementById('screen').className = '';
}
document.getElementById('select').onclick = () => document.getElementById('loader').click();
fadeOut('ingame', 'preload');
}
function uploadSavedataPending(file) {
runCommands.push(() => gba.loadSavedataFromFile(file));
}
function togglePause() {
var btn = document.getElementById('pause');
if (gba.paused) {
gba.runStable();
btn.textContent = "PAUSE";
} else {
gba.pause();
btn.textContent = "UNPAUSE";
}
}
function screenshot() {
window.open(gba.indirectCanvas.toDataURL('image/png'), 'screenshot');
}
function setVolume(value) {
gba.audio.masterVolume = Math.pow(2, value) - 1;
}
function setPixelated(pixelated) {
var screen = document.getElementById('screen');
var ctx = screen.getContext('2d');
if (ctx.imageSmoothingEnabled !== undefined) {
ctx.imageSmoothingEnabled = !pixelated;
}
}
function setupTouchControls() {
function press(code) {
window.dispatchEvent(new KeyboardEvent('keydown', {keyCode: code, bubbles: true}));
}
function release(code) {
window.dispatchEvent(new KeyboardEvent('keyup', {keyCode: code, bubbles: true}));
}
const map = {
up: 38, down: 40, left: 37, right: 39,
a: 88, // X key β†’ GBA A
b: 90, // Z key β†’ GBA B
l: 65, // A key β†’ L
r: 83, // S key β†’ R
start: 13, // Enter
select: 16 // Shift
};
['up','down','left','right','a','b','l','r','start','select'].forEach(key => {
const el = document.getElementById(key);
if (!el) return;
el.addEventListener('touchstart', e => { e.preventDefault(); press(map[key]); });
el.addEventListener('touchend', e => { e.preventDefault(); release(map[key]); });
el.addEventListener('touchcancel',e => { e.preventDefault(); release(map[key]); });
});
}
</script>
</head>
<body>
<div id="screen-container">
<canvas id="screen" width="480" height="320"></canvas>
</div>
<!-- UI Controls (top-left overlay) -->
<section id="controls">
<div id="preload">
<button class="bigbutton" id="select" onclick="document.getElementById('loader').click()">SELECT</button>
<input id="loader" type="file" accept=".gba" onchange="run(this.files[0])" style="display:none">
<button onclick="document.getElementById('saveloader').click()">Upload Save</button>
<input id="saveloader" type="file" onchange="uploadSavedataPending(this.files[0])" style="display:none">
</div>
<div id="ingame" class="hidden">
<button id="pause" class="bigbutton" onclick="togglePause()">PAUSE</button>
<button class="bigbutton" onclick="reset()">RESET</button>
<button onclick="gba.downloadSavedata()">Download Save</button>
<button onclick="screenshot()">Screenshot</button>
<label id="pixelated">
<input type="checkbox" onchange="setPixelated(this.checked)"> Pixelated
</label>
<div id="sound">
<input type="checkbox" checked onchange="gba.audio.masterEnable = this.checked"> Sound
<input type="range" min="0" max="1" value="1" step="any" oninput="setVolume(this.value)">
</div>
</div>
</section>
<!-- Touch Controls Overlay -->
<div id="touchControls">
<!-- D-Pad -->
<div id="dpad">
<button id="up">↑</button>
<button id="left">←</button>
<button id="right">β†’</button>
<button id="down">↓</button>
</div>
<!-- Face / Shoulders / Start/Select -->
<div id="faceButtons">
<div>
<button id="l" class="shoulder">L</button>
<button id="r" class="shoulder">R</button>
</div>
<div>
<button id="select" class="startselect">Select</button>
<button id="start" class="startselect">Start</button>
</div>
<div>
<button id="b">B</button>
<button id="a">A</button>
</div>
</div>
</div>
</body>
</html>