Skip to content

Instantly share code, notes, and snippets.

@ShayDavidson
Created May 31, 2024 08:04
Show Gist options
  • Save ShayDavidson/17af4898421f5bda2b453274f8f29763 to your computer and use it in GitHub Desktop.
Save ShayDavidson/17af4898421f5bda2b453274f8f29763 to your computer and use it in GitHub Desktop.
import { useCallback, useEffect, useRef, MutableRefObject } from 'react';
export interface UseGameLoopOptions {
shouldPauseOnBlur?: boolean;
shouldResumeOnFocus?: boolean;
}
export interface GameLoopContext {
state: MutableRefObject<'playing' | 'paused' | 'stopped'>;
start: () => void;
stop: () => void;
pause: () => void;
}
export function useGameLoop(cb: (dt: number) => void, options?: UseGameLoopOptions): GameLoopContext {
const state = useRef<'playing' | 'paused' | 'stopped'>('stopped');
const rafRef = useRef(NaN);
const start = useCallback(() => {
if (state.current === 'playing') return;
let lastTimestamp = new Date().getTime();
state.current = 'playing';
const handler = (): void => {
const currentTimestamp = new Date().getTime();
const dt = currentTimestamp - lastTimestamp;
lastTimestamp = currentTimestamp;
cb(dt);
rafRef.current = window.requestAnimationFrame(handler);
};
rafRef.current = window.requestAnimationFrame(handler);
}, [cb]);
const stop = useCallback(() => {
window.cancelAnimationFrame(rafRef.current);
rafRef.current = NaN;
state.current = 'stopped';
}, []);
const pause = useCallback(() => {
if (state.current !== 'playing') return;
window.cancelAnimationFrame(rafRef.current);
rafRef.current = NaN;
state.current = 'paused';
}, []);
useEffect(() => {
const blurHandler = (): void => {
if (state.current === 'playing') {
if (options?.shouldPauseOnBlur) {
pause();
}
}
};
const focusHandler = (): void => {
if (state.current === 'paused') {
if (options?.shouldResumeOnFocus) {
start();
}
}
};
window.addEventListener('blur', blurHandler);
window.addEventListener('focus', focusHandler);
return () => {
stop();
window.removeEventListener('blur', blurHandler);
window.removeEventListener('focus', focusHandler);
};
}, []);
return {
state,
start,
pause,
stop,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment