lucky / Touch 2.html
Studytime171's picture
Duplicate from Studytime171/Lalitgangwani
89610f7
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>GBA.js - Mobile Optimized</title>
<link rel="stylesheet" href="resources/main.css">
<style>
/* Mobile Fit and Overlay Styling */
body {
margin: 0;
padding: 0;
background-color: #000;
overflow: hidden; /* Prevent scrolling during gameplay */
touch-action: none; /* Disable default browser gestures */
}
#screen {
display: block;
margin: 0 auto;
max-width: 100vw;
max-height: 100vh;
image-rendering: pixelated;
object-fit: contain;
}
/* Optimized Gamepad Overlay */
#touchControls {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
display: none;
z-index: 100;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
padding: 20px;
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
-webkit-tap-highlight-color: transparent;
}
#touchControls button {
pointer-events: auto;
border: none;
font-weight: bold;
font-family: sans-serif;
text-transform: uppercase;
transition: opacity 0.1s;
}
#touchControls button:active {
opacity: 0.5;
filter: brightness(1.2);
}
.dpad-btn {
background: rgba(255, 255, 255, 0.15);
color: white;
border-radius: 10px;
font-size: 24px;
}
.action-btn {
width: 75px;
height: 75px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.25);
color: white;
font-size: 20px;
}
.shoulder-btn {
width: 70px;
height: 35px;
background: rgba(255, 255, 255, 0.15);
color: white;
border-radius: 5px;
font-size: 14px;
}
.meta-btn {
width: 60px;
height: 25px;
background: rgba(255, 255, 255, 0.15);
color: white;
border-radius: 15px;
font-size: 10px;
}
</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;
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.getAttribute('class') == 'dead') {
console.log('We appear to have crashed multiple times without reseting.');
return;
}
var crash = document.createElement('img');
crash.setAttribute('id', 'crash');
crash.setAttribute('src', 'resources/crash.png');
screen.parentElement.insertBefore(crash, screen);
screen.setAttribute('class', 'dead');
});
} catch (exception) {
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) {
gba.setBios(bios);
});
if (!gba.audio.context) {
var soundbox = document.getElementById('sound');
if(soundbox) soundbox.parentElement.removeChild(soundbox);
}
if (window.navigator.appName == 'Microsoft Internet Explorer') {
var pixelatedBox = document.getElementById('pixelated');
if(pixelatedBox) pixelatedBox.parentElement.removeChild(pixelatedBox);
}
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
document.getElementById('touchControls').style.display = 'flex';
}
setupTouchControls();
} else {
var dead = document.getElementById('controls');
if(dead) dead.parentElement.removeChild(dead);
}
}
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.setAttribute('class', 'dead');
e.removeEventListener('transitionend', removeSelf);
}
if (e2) {
e2.setAttribute('class', 'hidden');
setTimeout(function() {
e2.removeAttribute('class');
}, 0);
}
}
e.addEventListener('transitionend', removeSelf, false);
e.setAttribute('class', 'hidden');
}
function run(file) {
var dead = document.getElementById('loader');
dead.value = '';
var load = document.getElementById('select');
load.textContent = 'Loading...';
load.removeAttribute('onclick');
var pause = document.getElementById('pause');
pause.textContent = "PAUSE";
gba.loadRomFromFile(file, function(result) {
if (result) {
for (var i = 0; i < runCommands.length; ++i) {
runCommands[i]();
}
runCommands = [];
fadeOut('preload', 'ingame');
fadeOut('instructions', null, true);
gba.runStable();
} else {
load.textContent = 'FAILED';
setTimeout(function() {
load.textContent = 'SELECT';
load.onclick = function() { document.getElementById('loader').click(); }
}, 3000);
}
});
}
function reset() {
gba.pause();
gba.reset();
var load = document.getElementById('select');
load.textContent = 'SELECT';
var crash = document.getElementById('crash');
if (crash) {
var context = gba.targetCanvas.getContext('2d');
context.clearRect(0, 0, 480, 320);
gba.video.drawCallback();
crash.parentElement.removeChild(crash);
var canvas = document.getElementById('screen');
canvas.removeAttribute('class');
} else {
lcdFade(gba.context, gba.targetCanvas.getContext('2d'), gba.video.drawCallback);
}
load.onclick = function() { document.getElementById('loader').click(); }
fadeOut('ingame', 'preload');
}
function uploadSavedataPending(file) {
runCommands.push(function() { gba.loadSavedataFromFile(file) });
}
function togglePause() {
var e = document.getElementById('pause');
if (gba.paused) {
gba.runStable();
e.textContent = "PAUSE";
} else {
gba.pause();
e.textContent = "UNPAUSE";
}
}
function screenshot() {
var canvas = gba.indirectCanvas;
window.open(canvas.toDataURL('image/png'), 'screenshot');
}
function lcdFade(context, target, callback) {
var i = 0;
var drawInterval = setInterval(function() {
i++;
var pixelData = context.getImageData(0, 0, 240, 160);
for (var y = 0; y < 160; ++y) {
for (var x = 0; x < 240; ++x) {
var xDiff = Math.abs(x - 120);
var yDiff = Math.abs(y - 80) * 0.8;
var xFactor = (120 - i - xDiff) / 120;
var yFactor = (80 - i - ((y & 1) * 10) - yDiff + Math.pow(xDiff, 1 / 2)) / 80;
pixelData.data[(x + y * 240) * 4 + 3] *= Math.pow(xFactor, 1 / 3) * Math.pow(yFactor, 1 / 2);
}
}
context.putImageData(pixelData, 0, 0);
target.clearRect(0, 0, 480, 320);
if (i > 40) clearInterval(drawInterval);
else callback();
}, 50);
}
function setVolume(value) {
gba.audio.masterVolume = Math.pow(2, value) - 1;
}
function setPixelated(pixelated) {
var screen = document.getElementById('screen');
var context = screen.getContext('2d');
context.imageSmoothingEnabled = !pixelated;
}
function setupTouchControls() {
function pressKey(code) { window.dispatchEvent(new KeyboardEvent('keydown', {keyCode: code})); }
function releaseKey(code) { window.dispatchEvent(new KeyboardEvent('keyup', {keyCode: code})); }
const mapping = {
'up': 38, 'down': 40, 'left': 37, 'right': 39,
'a': 88, 'b': 90, 'l': 65, 'r': 83,
'start': 13, 'select': 16
};
Object.keys(mapping).forEach(id => {
const el = document.getElementById(id);
if(el) {
el.addEventListener('touchstart', (e) => { e.preventDefault(); pressKey(mapping[id]); });
el.addEventListener('touchend', (e) => { e.preventDefault(); releaseKey(mapping[id]); });
}
});
}
</script>
</head>
<body>
<canvas id="screen" width="480" height="320"></canvas>
<section id="controls">
<div id="preload">
<button class="bigbutton" id="select" onclick="document.getElementById('loader').click()">SELECT ROM</button>
<input id="loader" type="file" accept=".gba" onchange="run(this.files[0]);" style="display:none">
</div>
<div id="ingame" class="hidden">
<button id="pause" onclick="togglePause()">PAUSE</button>
<button onclick="reset()">RESET</button>
</div>
</section>
<div id="touchControls">
<div id="dpad-container" style="display: grid; grid-template-columns: repeat(3, 65px); grid-template-rows: repeat(3, 65px); gap: 5px;">
<button id="up" class="dpad-btn" style="grid-column: 2; grid-row: 1;"></button>
<button id="left" class="dpad-btn" style="grid-column: 1; grid-row: 2;"></button>
<button id="right" class="dpad-btn" style="grid-column: 3; grid-row: 2;"></button>
<button id="down" class="dpad-btn" style="grid-column: 2; grid-row: 3;"></button>
</div>
<div id="action-container" style="display: flex; flex-direction: column; align-items: flex-end; gap: 20px;">
<div style="display: flex; gap: 10px;">
<button id="l" class="shoulder-btn">L</button>
<button id="r" class="shoulder-btn">R</button>
</div>
<div style="display: flex; gap: 25px; margin-right: 10px;">
<button id="b" class="action-btn">B</button>
<button id="a" class="action-btn">A</button>
</div>
<div style="display: flex; gap: 15px;">
<button id="select" class="meta-btn">SELECT</button>
<button id="start" class="meta-btn">START</button>
</div>
</div>
</div>
</body>
</html>