UNPKG

prendy

Version:

Make games with prerendered backdrops using babylonjs and repond

113 lines (112 loc) 4.94 kB
import { getRefs, getState, startNewItemEffect, stopNewEffect } from "repond"; import { meta } from "../../meta"; import { getSafeCamName, getSafeSegmentName } from "./cameraChange"; import { getGlobalState } from "./global"; export const BEFORE_LOOP_PADDING = 0.05; // seconds before video end to do loop (50ms) export function getSliceVidVideo(itemId) { const sliceVidState = getState().sliceVids[itemId]; const { stateVidId_playing } = sliceVidState; if (!stateVidId_playing) return; const backdropVidRefs = getRefs().stateVids[stateVidId_playing]; return backdropVidRefs.videoElement; } export function getSliceVidWaitingVideo(itemId) { const sliceVidState = getState().sliceVids[itemId]; const { stateVidId_waiting } = sliceVidState; if (!stateVidId_waiting) return; const backdropVidRefs = getRefs().stateVids[stateVidId_waiting]; return backdropVidRefs.videoElement; } // temporary rule, that gets removed when it finishes export function doWhenSliceVidStateChanges(sliceVidId, checkShouldRun, callback) { const { placeInfoByName } = meta.assets; const initialVidState = getState().sliceVids[sliceVidId].sliceVidState; if (checkShouldRun(initialVidState)) { callback(); return null; } const effectId = "doWhenSliceVidStateChanges" + Math.random() + Math.random(); startNewItemEffect({ id: effectId, run: ({ newValue: newVidState }) => { if (!checkShouldRun(newVidState)) return; stopNewEffect(effectId); callback(); }, check: { type: "sliceVids", prop: "sliceVidState", id: sliceVidId }, step: "sliceVidStateUpdates", atStepEnd: true, }); return effectId; } export function doWhenSliceVidPlaying(sliceVidId, callback) { return doWhenSliceVidStateChanges(sliceVidId, (newState) => newState === "play", callback); } export async function doWhenSliceVidPlayingAsync(sliceVidId) { return new Promise((resolve, _reject) => { doWhenSliceVidPlaying(sliceVidId, resolve); }); } export function getSliceEndTime(slice) { return slice.time + slice.duration - BEFORE_LOOP_PADDING; } export function getSliceForPlace(place, camName, segment) { const { placeInfoByName } = meta.assets; const { nowPlaceName: safePlace } = getGlobalState(); const safeCam = getSafeCamName(camName); if (place !== safePlace) console.warn("tried to getSliceForPlace with non current place", place); const safeSegmentName = getSafeSegmentName({ segment, cam: safeCam, place: safePlace }); // NOTE might be a way to avoid using any but is internal so okay for now const placeSegmentTimesByCamera = placeInfoByName[safePlace].segmentTimesByCamera; const typedCamName = safeCam; const placeSegmentDurations = placeInfoByName[safePlace].segmentDurations; const newTime = placeSegmentTimesByCamera[typedCamName][safeSegmentName]; const newDuration = placeSegmentDurations[safeSegmentName]; return { time: newTime, duration: newDuration }; } export function checkIfVideoUnloading(placeName) { const itemState = getState().sliceVids[placeName]; const { sliceVidState } = itemState; return sliceVidState === "unloaded" || sliceVidState === "waitingForUnload"; } export function checkIfVideoAlreadyChanging(placeName) { const itemState = getState().sliceVids[placeName]; const { sliceVidState } = itemState; const isAlreadyLoopingOrChangingSlice = sliceVidState === "beforeDoLoop" || sliceVidState === "beforeChangeSlice" || sliceVidState === "waitingForDoLoop" || sliceVidState === "waitingForChangeSlice"; return isAlreadyLoopingOrChangingSlice; } // Runs on changes to tick, in the checkVideoLoop flow export function checkForVideoLoop(placeName) { // maybe add a check, if the video loop has stayed on beforeDoLoop or beforeChangeSlice for too many frames, then do something? const itemState = getState().sliceVids[placeName]; const { nowSlice } = itemState; const backdropVid = getSliceVidVideo(placeName); if (checkIfVideoUnloading(placeName)) return false; const currentTime = backdropVid?.currentTime ?? 0; const endTime = getSliceEndTime(nowSlice); const isAtOrAfterEndOfLoop = currentTime >= endTime; const isBeforeStartOfLoop = currentTime < nowSlice.time; // if the current time is before the video slices start time // const isAlreadyLoopingOrChangingSlice = checkIfVideoAlreadyChanging(placeName); const shouldLoop = isAtOrAfterEndOfLoop || isBeforeStartOfLoop; return shouldLoop; } // { // getSliceVidVideo, // getSliceVidWaitingVideo, // doWhenSliceVidPlayingAsync, // doWhenSliceVidStateChanges, // doWhenSliceVidPlaying, // getSliceEndTime, // getSliceForPlace, // checkForVideoLoop, // checkIfVideoUnloading, // checkIfVideoAlreadyChanging, // };