fix the bugs with skipping
This commit is contained in:
		| @@ -13,9 +13,11 @@ calvin (mathstruck) "Wow, did you know that $a^2+b^2=c^2$?" | ||||
|  | ||||
| calvin (thinking) "Something else" | ||||
|  | ||||
| bridget (surprised) "Me again" | ||||
| bridget (surprised) "Me again000000" | ||||
|  | ||||
| kit (smiling) "I'm Kit!" | ||||
| kit (smiling) "I'm Kit 1!" | ||||
|  | ||||
| kit (smiling) "I'm Kit 2!" | ||||
|  | ||||
| board "" | ||||
|  | ||||
|   | ||||
| @@ -1,26 +1,51 @@ | ||||
| import { useEffect, useLayoutEffect, useState } from "react"; | ||||
| import { ForwardedRef, forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react"; | ||||
| import { MathText } from "./MathText"; | ||||
|  | ||||
| export const DialogText = (props: {children: string, onFinish?: () => void}) => { | ||||
| 	const {children: str, onFinish} = props; | ||||
| export type DialogTextImperatives = { | ||||
| 	skip(): void; | ||||
| } | ||||
|  | ||||
| export const DialogText = forwardRef((props: {children: string, speed?: number, onFinish?: () => void}, forwardedRef: ForwardedRef<DialogTextImperatives>) => { | ||||
| 	const {children: str, onFinish, speed = 15} = props; | ||||
| 	const [len, setLen] = useState(0); | ||||
| 	const interval = useRef<unknown>(null); | ||||
|  | ||||
| 	useImperativeHandle(forwardedRef, () => { | ||||
| 		return { | ||||
| 			skip() { | ||||
| 				setLen(str.length); | ||||
| 			} | ||||
| 		} | ||||
| 	}, [str, setLen]); | ||||
|  | ||||
| 	useLayoutEffect(() => { | ||||
| 		setLen(0); | ||||
| 	}, [str]); | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		const interval = setInterval(() => { | ||||
| 			setLen(l => Math.max(l+1, str.length)); | ||||
| 		}, 70); | ||||
| 		if (len === str.length) { | ||||
| 			// clearInterval(interval); | ||||
| 			onFinish && onFinish(); | ||||
| 		} | ||||
| 		interval.current = setInterval(() => { | ||||
| 			setLen(l => { | ||||
| 				return Math.min(l+1, str.length) | ||||
| 			}); | ||||
| 		}, 1000/speed); | ||||
| 		return () => { | ||||
| 			clearInterval(interval); | ||||
| 			if (interval.current) { | ||||
| 				clearInterval(interval.current as any); | ||||
| 				interval.current = null; | ||||
| 			} | ||||
| 		}; | ||||
| 	}, [str, setLen]); | ||||
|  | ||||
| 	useLayoutEffect(() => { | ||||
| 		if (len === str.length) { | ||||
| 			if (interval.current) { | ||||
| 				clearInterval(interval.current as any); | ||||
| 				interval.current = null; | ||||
| 			} | ||||
| 			console.log("onFinish"); | ||||
| 			onFinish && onFinish(); | ||||
| 		} | ||||
| 	}, [len]); | ||||
|  | ||||
| 	return <MathText>{str.slice(0, len)}</MathText> | ||||
| } | ||||
| }); | ||||
| @@ -3,7 +3,7 @@ import { Mathuscript, parseMathuscript } from "./parse"; | ||||
| import { useCallback, useMemo, useRef, useState } from "react"; | ||||
| import { MathText } from "./MathText"; | ||||
| import { characterData } from "./data"; | ||||
| import { DialogText } from "./DialogText"; | ||||
| import { DialogText, DialogTextImperatives } from "./DialogText"; | ||||
|  | ||||
| type VisualState = { | ||||
| 	turn: number, | ||||
| @@ -45,7 +45,6 @@ const afterStep = (state: VisualState, step: Mathuscript[number]): VisualState = | ||||
| 		dialog.emotion = char.emotion; | ||||
| 		dialog.text = step.text; | ||||
| 	} | ||||
| 	console.log(newState); | ||||
| 	return newState; | ||||
| } | ||||
|  | ||||
| @@ -65,16 +64,18 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 	const [index, setIndex] = useState(0); | ||||
| 	const [visualState, setVisualState] = useState<VisualState>({turn: 0, characters: [], board: {text: ""}, dialog: {name: null, emotion: "", text: ""}}); | ||||
| 	const dialogGoing = useRef(false); | ||||
| 	const dialogTextRef = useRef<DialogTextImperatives>(null); | ||||
|  | ||||
| 	const doStep = useCallback(() => { | ||||
| 		goAgain.current = false; | ||||
| 		if (dialogGoing.current) { | ||||
| 			console.log("dialog running"); | ||||
| 			if (dialogTextRef.current) { | ||||
| 				dialogTextRef.current.skip(); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 		goAgain.current = false; | ||||
| 		const step = parsedScript[index]; | ||||
| 		if (step) { | ||||
| 			console.log(step); | ||||
| 			setIndex(i => i+1); | ||||
| 			setVisualState(state => afterStep(state, step)); | ||||
| 			if (step.name === "board") { | ||||
| @@ -87,6 +88,10 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 		} | ||||
| 	}, [index, parsedScript, setIndex, setVisualState]); | ||||
|  | ||||
| 	const onDialogFinish = useCallback(() => { | ||||
| 		dialogGoing.current = false; | ||||
| 	}, []); | ||||
|  | ||||
| 	if (goAgain.current) { | ||||
| 		doStep(); | ||||
| 	} | ||||
| @@ -218,9 +223,7 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 								`}> | ||||
| 									<strong>{speakingChar.displayName}</strong> {visualState.dialog.emotion && <em>({visualState.dialog.emotion})</em>} | ||||
| 								</div> | ||||
| 								<DialogText onFinish={() => { | ||||
| 									dialogGoing.current = false; | ||||
| 								}}> | ||||
| 								<DialogText onFinish={onDialogFinish} ref={dialogTextRef}> | ||||
| 									{visualState.dialog.text} | ||||
| 								</DialogText> | ||||
| 							</> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan