UNPKG

pixi-fusion

Version:

This module offers a set of common components needed for playing games.

100 lines (99 loc) 3.8 kB
import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Viewport as ViewportContainer } from "pixi-viewport"; import { Layer } from "../layer"; import { useStage, useWorld } from "../hooks"; import { LayerContext } from "../layer/Layer.context"; import { CameraContext } from "./Camera.context"; export const Camera = ({ children, clampZoom }) => { const [isReady, setIsReady] = useState(false); const [followContainer, setFollowContainer] = useState(null); const [ensureVisibleOptions, setEnsureVisibleOptions] = useState(null); const { application, size } = useWorld(); const { addObject: addObjectToStage, removeObject: removeObjectFromStage } = useStage(); const [things, setThings] = useState([]); const viewport = useMemo(() => application ? new ViewportContainer({ worldHeight: size.height, worldWidth: size.width, screenHeight: application.canvas.height, screenWidth: application.canvas.width, events: application?.renderer?.events }) : null, [size, application]); const addObject = useCallback((thing) => { setThings((oldThings) => [...oldThings, thing]); }, []); const removeObject = useCallback((thing) => { setThings((oldThings) => oldThings.filter(({ uid }) => uid === thing.uid)); }, []); const conextValue = useMemo(() => ({ addObject, removeObject }), [addObject, removeObject]); useEffect(() => { if (viewport && clampZoom && application) { viewport.clampZoom(clampZoom); } }, [clampZoom, application, viewport]); useEffect(() => { if (viewport) { if (size.width) { viewport.width = size.width; } if (size.height) { viewport.height = size.height; } } }, [size, viewport, application]); useEffect(() => { if (!application || !viewport) { return; } viewport?.moveCenter(0, 0); }, [viewport, size, application]); useEffect(() => { if (!viewport) { return; } addObjectToStage(viewport); setIsReady(true); return () => { removeObjectFromStage(viewport); setIsReady(false); }; }, [viewport, addObjectToStage, removeObjectFromStage]); useEffect(() => { if (!viewport || !isReady) { return; } viewport.addChild(...things); return () => { viewport.removeChild(...things); }; }, [things, viewport, isReady]); useEffect(() => { if (isReady && viewport && followContainer) { viewport.follow(followContainer, { radius: 300 }); } }, [isReady, viewport, followContainer]); useEffect(() => { if (isReady && viewport && ensureVisibleOptions) { viewport.ensureVisible(ensureVisibleOptions.x, ensureVisibleOptions.y, ensureVisibleOptions.width, ensureVisibleOptions.height, ensureVisibleOptions.resizeToFit); } }, [isReady, viewport, ensureVisibleOptions]); const followCallback = useCallback((container) => { setFollowContainer(container); }, []); const ensureVisibleCallback = useCallback((options) => { setEnsureVisibleOptions(options); }, []); const value = useMemo(() => { return { follow: followCallback, ensureVisible: ensureVisibleCallback }; }, [followCallback, ensureVisibleCallback]); return (React.createElement(CameraContext.Provider, { value: value }, React.createElement(LayerContext.Provider, { value: conextValue }, React.createElement(Layer, null, children)))); };