Last active
January 9, 2021 23:22
-
-
Save a-type/baf6a44d5fae1d39d3cb2ee8d22f91af to your computer and use it in GitHub Desktop.
use-javelin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ComponentOf, ComponentType, query, Selector } from '@javelin/ecs'; | |
import { useEffect, useRef, useState } from 'react'; | |
import { useWorld } from './useWorld'; | |
function compareIdLists(a: number[], b: number[]) { | |
return a.sort().join('') === b.sort().join(''); | |
} | |
export function useEntities(...filters: Selector) { | |
const [entities, setEntities] = useState<number[]>([]); | |
const { registerSubsystem } = useWorld(); | |
const [q] = useState(() => query(...filters)); | |
const idListRef = useRef<number[]>([]); | |
const lastIdListRef = useRef<number[]>([]); | |
useEffect(() => { | |
// TODO: fix perf of this | |
return registerSubsystem((world) => { | |
for (const [e] of q(world)) { | |
idListRef.current.push(e); | |
} | |
// ugly but prevents unnecessary re-renders | |
if (!compareIdLists(lastIdListRef.current, idListRef.current)) { | |
setEntities(idListRef.current); | |
} | |
lastIdListRef.current = idListRef.current; | |
idListRef.current = []; | |
}); | |
}, [registerSubsystem, idListRef, lastIdListRef, q]); | |
return entities; | |
} | |
export function useComponent<T extends ComponentType>( | |
entityId: number, | |
Type: T, | |
) { | |
const { world } = useWorld(); | |
const [comp] = useState<ComponentOf<T>>(() => | |
world.getComponent(entityId, Type), | |
); | |
return comp; | |
} | |
export function useObservedComponent<T extends ComponentType>( | |
entityId: number, | |
Type: T, | |
) { | |
const { world } = useWorld(); | |
const comp = useComponent(entityId, Type); | |
const [, setVersion] = useState(0); | |
useEffect(() => { | |
let frame: number; | |
function loop() { | |
if (world.isComponentChanged(comp)) { | |
setVersion((c) => (c + 1) % Number.MAX_SAFE_INTEGER); | |
} | |
frame = requestAnimationFrame(loop); | |
} | |
loop(); | |
return () => { | |
cancelAnimationFrame(frame); | |
}; | |
}, [world, comp]); | |
return comp; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment