mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Press to start on mobile (#622)
This commit is contained in:
commit
abd5e44ede
|
@ -43,13 +43,12 @@ const AppContainer = styled.main`
|
|||
|
||||
const StartButtonWrapper = styled.button`
|
||||
margin: auto;
|
||||
font-size: 3em;
|
||||
font-size: 2em;
|
||||
padding: 1em;
|
||||
text-transform: uppercase;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.5em;
|
||||
aspect-ratio: 240 / 160;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -62,7 +61,8 @@ const StartButtonWrapper = styled.button`
|
|||
|
||||
interface MgbaWrapperProps {
|
||||
gameUrl: string;
|
||||
startNotPlaying?: boolean;
|
||||
isPlaying?: boolean;
|
||||
setIsPlaying?: (isPlaying: boolean) => void;
|
||||
}
|
||||
|
||||
export const MgbaStandalone: FC<MgbaWrapperProps> = (props) => (
|
||||
|
@ -71,12 +71,8 @@ export const MgbaStandalone: FC<MgbaWrapperProps> = (props) => (
|
|||
</AppContainer>
|
||||
);
|
||||
|
||||
export interface MgbaWrapperHandle extends MgbaHandle {
|
||||
hardReset: () => void;
|
||||
}
|
||||
|
||||
export const MgbaWrapper = forwardRef<MgbaWrapperHandle, MgbaWrapperProps>(
|
||||
({ gameUrl, startNotPlaying = false }, ref) => {
|
||||
export const MgbaWrapper = forwardRef<MgbaHandle, MgbaWrapperProps>(
|
||||
({ gameUrl, isPlaying = true, setIsPlaying }, ref) => {
|
||||
const [{ volume, bindings }, setState] = useLocalStorage(
|
||||
{ volume: 1.0, bindings: DefaultBindingsSet() },
|
||||
"agbrswebplayer"
|
||||
|
@ -108,8 +104,6 @@ export const MgbaWrapper = forwardRef<MgbaWrapperHandle, MgbaWrapperProps>(
|
|||
|
||||
useAvoidItchIoScrolling();
|
||||
|
||||
const [isPlaying, setIsPlaying] = useState(!startNotPlaying);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showBindings && (
|
||||
|
@ -133,7 +127,7 @@ export const MgbaWrapper = forwardRef<MgbaWrapperHandle, MgbaWrapperProps>(
|
|||
paused={paused}
|
||||
/>
|
||||
) : (
|
||||
<StartButton onClick={() => setIsPlaying(true)} />
|
||||
<StartButton onClick={() => setIsPlaying && setIsPlaying(true)} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -179,7 +173,7 @@ function BindingsWindow({
|
|||
|
||||
function StartButton({ onClick }: { onClick: () => void }) {
|
||||
return (
|
||||
<StartButtonWrapper onClick={onClick}>Press to start</StartButtonWrapper>
|
||||
<StartButtonWrapper onClick={onClick}>Touch to start</StartButtonWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ import DPad from "./gba-parts/dpad.png";
|
|||
import ABButtons from "./gba-parts/ab.png";
|
||||
import Select from "./gba-parts/SELECT.png";
|
||||
import Start from "./gba-parts/START.png";
|
||||
import { MgbaWrapperHandle } from "./mgba/mgbaWrapper";
|
||||
import { GbaKey } from "./mgba/bindings";
|
||||
import { MgbaHandle } from "./mgba/mgba";
|
||||
|
||||
const MobileControls = styled.div`
|
||||
display: flex;
|
||||
|
@ -48,7 +48,7 @@ const MobileControlsRow = styled.div<{
|
|||
${(props) => props.$centered && `justify-content: center;`}
|
||||
`;
|
||||
|
||||
const useSimpleButton = (mgba: MgbaWrapperHandle, button: GbaKey) => {
|
||||
const useSimpleButton = (mgba: MgbaHandle, button: GbaKey) => {
|
||||
return useMemo(() => {
|
||||
return {
|
||||
onTouchStart: () => {
|
||||
|
@ -80,7 +80,7 @@ const relativeTouch = (touch: Touch) => {
|
|||
return relativePosition;
|
||||
};
|
||||
|
||||
const useDpadTouch = (mgba: MgbaWrapperHandle) => {
|
||||
const useDpadTouch = (mgba: MgbaHandle) => {
|
||||
const [previouslyPressedButtons, setTouchedButtons] = useState<Set<GbaKey>>(
|
||||
new Set()
|
||||
);
|
||||
|
@ -139,7 +139,7 @@ const useDpadTouch = (mgba: MgbaWrapperHandle) => {
|
|||
}, [mgba, previouslyPressedButtons]);
|
||||
};
|
||||
|
||||
const useAbTouch = (mgba: MgbaWrapperHandle) => {
|
||||
const useAbTouch = (mgba: MgbaHandle) => {
|
||||
const [previouslyPressedButtons, setTouchedButtons] = useState<Set<GbaKey>>(
|
||||
new Set()
|
||||
);
|
||||
|
@ -182,7 +182,7 @@ const useAbTouch = (mgba: MgbaWrapperHandle) => {
|
|||
}, [mgba, previouslyPressedButtons]);
|
||||
};
|
||||
|
||||
export const MobileController: FC<{ mgba: MgbaWrapperHandle }> = ({ mgba }) => {
|
||||
export const MobileController: FC<{ mgba: MgbaHandle }> = ({ mgba }) => {
|
||||
return (
|
||||
<MobileControls onContextMenu={(evt) => evt.preventDefault()}>
|
||||
<MobileControlsRow $size={MobileControlsSize.Small}>
|
||||
|
@ -218,7 +218,7 @@ export const MobileController: FC<{ mgba: MgbaWrapperHandle }> = ({ mgba }) => {
|
|||
/>
|
||||
</MobileControlsRow>
|
||||
<MobileControlsRow $size={MobileControlsSize.Small} $centered>
|
||||
<button onClick={() => mgba.hardReset()}>Restart</button>
|
||||
<button onClick={() => mgba.restart()}>Restart</button>
|
||||
</MobileControlsRow>
|
||||
</MobileControls>
|
||||
);
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
|
||||
import styled from "styled-components";
|
||||
import { CenteredBlock, ContentBlock } from "./contentBlock";
|
||||
import MgbaWrapper, { MgbaWrapperHandle } from "./mgba/mgbaWrapper";
|
||||
import MgbaWrapper from "./mgba/mgbaWrapper";
|
||||
import Image from "next/image";
|
||||
|
||||
import left from "./gba-parts/left.png";
|
||||
import right from "./gba-parts/right.png";
|
||||
import { MobileController } from "./mobileController";
|
||||
import { useMemo, useRef } from "react";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { GbaKey } from "./mgba/bindings";
|
||||
import { useClientValue } from "./useClientValue.hook";
|
||||
import { MgbaHandle } from "./mgba/mgba";
|
||||
|
||||
const ExternalLink = styled.a`
|
||||
text-decoration: none;
|
||||
|
@ -19,6 +20,10 @@ const ExternalLink = styled.a`
|
|||
border: solid #fad288 2px;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px;
|
||||
|
||||
&:hover {
|
||||
border: solid black 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
const HelpLinks = styled.div`
|
||||
|
@ -27,7 +32,7 @@ const HelpLinks = styled.div`
|
|||
`;
|
||||
|
||||
const GameDisplay = styled.div`
|
||||
height: min(calc(100vw / 1.5), 40vh);
|
||||
height: min(calc(100vw / 1.5), min(90vh, 480px));
|
||||
max-width: 100vw;
|
||||
margin-top: 20px;
|
||||
overflow: hidden;
|
||||
|
@ -36,7 +41,7 @@ const GameDisplay = styled.div`
|
|||
const GamePanelWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
align-items: end;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
|
@ -60,12 +65,16 @@ const GameSide = styled.div`
|
|||
|
||||
const isTouchScreen = () => navigator.maxTouchPoints > 1;
|
||||
|
||||
function shouldStartPlaying(isTouchScreen: boolean | undefined) {
|
||||
if (isTouchScreen === undefined) return false;
|
||||
return !isTouchScreen;
|
||||
}
|
||||
|
||||
const MgbaWithControllerSides = () => {
|
||||
const mgba = useRef<MgbaWrapperHandle>(null);
|
||||
const mgba = useRef<MgbaHandle>(null);
|
||||
|
||||
const mgbaHandle = useMemo(
|
||||
() => ({
|
||||
hardReset: () => mgba.current?.hardReset(),
|
||||
restart: () => mgba.current?.restart(),
|
||||
buttonPress: (key: GbaKey) => mgba.current?.buttonPress(key),
|
||||
buttonRelease: (key: GbaKey) => mgba.current?.buttonRelease(key),
|
||||
|
@ -73,8 +82,12 @@ const MgbaWithControllerSides = () => {
|
|||
[]
|
||||
);
|
||||
|
||||
const [isPlaying, setIsPlaying] = useState<boolean>();
|
||||
const shouldUseTouchScreenInput = useClientValue(isTouchScreen);
|
||||
|
||||
const playEmulator =
|
||||
isPlaying ?? shouldStartPlaying(shouldUseTouchScreenInput);
|
||||
|
||||
return (
|
||||
<>
|
||||
<GameDisplay>
|
||||
|
@ -83,7 +96,12 @@ const MgbaWithControllerSides = () => {
|
|||
<Image src={left} alt="" />
|
||||
</GameSide>
|
||||
<GameDisplayWindow>
|
||||
<MgbaWrapper gameUrl="combo.gba.gz" ref={mgba} />
|
||||
<MgbaWrapper
|
||||
gameUrl="combo.gba.gz"
|
||||
ref={mgba}
|
||||
isPlaying={playEmulator}
|
||||
setIsPlaying={setIsPlaying}
|
||||
/>
|
||||
</GameDisplayWindow>
|
||||
<GameSide>
|
||||
<Image src={right} alt="" />
|
||||
|
|
Loading…
Reference in a new issue