UNPKG

prendy

Version:

Make games with prerendered backdrops using babylonjs and repond

196 lines (164 loc) 7.65 kB
import { getRefs, getState, makeEffects, onNextTick, setState } from "repond"; import { getSafeSegmentName, updateTexturesForNowCamera } from "../../helpers/prendyUtils/cameraChange"; import { AnyCameraName, AnySegmentName, CameraNameByPlace, PlaceName, SegmentNameByPlace } from "../../types"; import { meta } from "../../meta"; import { focusSlateOnFocusedDoll } from "../../helpers/babylonjs/slate"; export const globalVideoEffects = makeEffects(({ itemEffect, effect }) => ({ whenWantToUpdateBackdropFrameInfo: effect({ run({}, frameDuration) { const { nowPlaceName, nowSegmentName, goalSegmentName, goalSegmentNameAtLoop, goalSegmentNameWhenVidPlays, goalPlaceName, // checking this as a very early way to know if its loading a new place, goToNewPlace , which sets goalSegmentName and goalCamName also sets goalPlaceName isLoadingBetweenPlaces, readyToSwapPlace, // backdropTime, backdropFrame, } = getState().global.main; const { goalCamNameAtLoop, goalCamName, nowCamName, gameTimeSpeed } = getState().global.main; // const videoIsOutsideOfCurrentLoop = checkForVideoLoop(nowPlaceName as PlaceName); // const videoIsAlreadyChanging = checkIfVideoAlreadyChanging(nowPlaceName); // all other goal values get cleared each time let new_goalSegmentNameAtLoop = goalSegmentNameAtLoop; let new_goalCamNameAtLoop = goalCamNameAtLoop; let new_goalCamName = goalCamName; let new_goalSegmentName = goalSegmentName; let new_wantToLoop = false; let new_shouldKeepTime = true; const { placeInfoByName } = meta.assets!; const nowPlaceInfo = placeInfoByName[nowPlaceName]; // if there's a goalPlaceName, so its starting to load the next-place if (goalPlaceName) { // NOTE , might still want to loop the videos when it's loading a new place ? // but it should fade out so hopefully don't need to, it might just show a little bit of the next part of the video while fading , but it can be fixed here if wanted // return; } if (isLoadingBetweenPlaces) return; if (new_wantToLoop && (goalCamNameAtLoop || goalSegmentNameAtLoop)) { new_goalCamName = goalCamName || goalCamNameAtLoop; new_goalSegmentName = goalSegmentName || goalSegmentNameAtLoop; new_goalCamNameAtLoop = null; new_goalSegmentNameAtLoop = null; } if (new_goalSegmentName || new_goalCamName) { // set the other value if its undefined new_goalCamName = new_goalCamName || nowCamName; new_goalSegmentName = new_goalSegmentName || nowSegmentName; // make sure its a safe segment // TODO retype intital state to have segments as strings new_goalSegmentName = getSafeSegmentName({ cam: new_goalCamName as CameraNameByPlace[PlaceName] & AnyCameraName, place: nowPlaceName as PlaceName, segment: new_goalSegmentName as SegmentNameByPlace[PlaceName] & AnySegmentName, useStorySegmentRules: true, // NOTE this could mess with things when manually chaning segment }); // if either the decided segment or camera is different to the now segment and camera if (!(new_goalCamName === nowCamName && new_goalSegmentName === nowSegmentName)) { new_wantToLoop = false; } } // if changing segments, don't keep the duration of the currently playing backdrop (which is good for changing cameras and keeping the same loop at different angles) if (new_goalSegmentName !== nowSegmentName) { new_shouldKeepTime = false; } // ------------------------------------------------ // Backrop times: let new_backdropTime = backdropTime + frameDuration * gameTimeSpeed; const backdropInfo = nowPlaceInfo.backdropsByCamera[nowCamName as AnyCameraName][nowSegmentName as AnySegmentName]; const { frameRate, totalFrames } = backdropInfo; // if (new_backdropTime > segmentDuration) { // // if the time is over the duration, then it should loop // new_backdropTime = 0; // new_wantToLoop = true; // } let new_backdropFrame = Math.floor((new_backdropTime * frameRate) / 1000); if (new_backdropFrame >= totalFrames) { new_backdropFrame = 0; new_backdropTime = 0; new_wantToLoop = true; } // NOTE I think it always keeps the segment time when changing cameras // ------------------------------------------------ // set State for global and sliceVids const somethingChanged = goalSegmentName !== null || new_goalSegmentNameAtLoop !== goalSegmentNameAtLoop || new_goalSegmentName !== goalSegmentNameWhenVidPlays || goalCamName !== null || new_goalCamNameAtLoop !== goalCamNameAtLoop || new_backdropTime !== backdropTime || new_backdropFrame !== backdropFrame; if (!somethingChanged) return; // onNextTick(() => { setState({ global: { main: { goalSegmentName: null, goalSegmentNameAtLoop: new_goalSegmentNameAtLoop, nowSegmentName: new_goalSegmentName ?? nowSegmentName, // goalCamName: null, // goalCamName: new_goalCamName ?? nowCamName, nowCamName: new_goalCamName ?? nowCamName, goalCamNameAtLoop: new_goalCamNameAtLoop, // switchSegment_keepProgress backdropFrame: new_backdropFrame, backdropTime: new_backdropTime, }, }, }); // }); }, // check every frame so it can handle goal things that didnt get set yet because there was already a waiting slice vid! check: { type: ["global"], id: ["main"], prop: ["frameTick"] }, step: "updateBackdropFrameInfo", // atStepEnd: true, // NOTE changed this recently }), // note no setState's done in here so its running on subscribe whenNowCameraChanges: effect({ run(diffInfo) { const globalState = getState().global.main; const { goalPlaceName } = globalState; // if (goalPlaceName !== null) return; const { nowCamName } = getState().global.main; const globalChangedBools = diffInfo.propsChangedBool.global.main; const placeChanged = globalChangedBools?.nowPlaceName; const cameraChanged = globalChangedBools?.nowCamName; if (!cameraChanged && !placeChanged) return; // if the place or camera changed // onNextTick(() => { // onNextTick(() => { // onNextTick(() => { // onNextTick(() => { // onNextTick(() => { updateTexturesForNowCamera(nowCamName as AnyCameraName); // }); // }); // }); // }); // }); }, check: { prop: ["nowCamName"], type: ["global"] }, step: "cameraChange", atStepEnd: true, }), // __________________ // Changing segments // NOTE FIXME TODO WARNING - this might not be still okay to use // it might be okay to run when nowCamName changed (since it always swaps the video between a-b vid_wait to vid_play whenPlayingVidElementsChanged: itemEffect({ run({ itemId: videoPlaceName }) { // so video texture updates for looping vids (and when slice changes) const { nowPlaceName } = getState().global.main; const globalRefs = getRefs().global.main; if (videoPlaceName !== nowPlaceName) return; }, check: { type: "sliceVids", prop: "newPlayingVidStartedTime" }, step: "cameraChange", atStepEnd: true, }), }));