Skip to content

Commit 610f957

Browse files
author
Philipp Molitor
committed
make context optional and improve unloading routine
1 parent c1d3112 commit 610f957

File tree

2 files changed

+47
-44
lines changed

2 files changed

+47
-44
lines changed

src/components/UnityRenderer.ts

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export type UnityRendererProps = Omit<
88
HTMLAttributes<HTMLCanvasElement>,
99
'ref'
1010
> & {
11-
context: UnityContext;
11+
context?: UnityContext;
1212
onUnityProgressChange?: (progress: number) => void;
1313
onUnityReadyStateChange?: (ready: boolean) => void;
1414
onUnityError?: (error: Error) => void;
@@ -31,8 +31,8 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
3131
onUnityError,
3232
...canvasProps
3333
}: UnityRendererProps): JSX.Element | null => {
34-
const [loader, setLoader] = useState<UnityLoaderService>();
35-
const [ctx, setCtx] = useState<UnityContext>(context);
34+
const [loader] = useState(new UnityLoaderService());
35+
const [ctx, setCtx] = useState<UnityContext | undefined>(context);
3636

3737
// We cannot actually render the `HTMLCanvasElement`, so we need the `ref`
3838
// for Unity and a `JSX.Element` for React rendering.
@@ -70,18 +70,20 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
7070
* after the unmounting has completed.
7171
*/
7272
function unmount(onComplete?: () => void) {
73-
ctx.shutdown(() => {
74-
// remove the loader script from the DOM
75-
if (loader) loader.unmount();
76-
73+
ctx?.shutdown(() => {
7774
// reset progress / ready state
7875
if (onUnityProgressChange) onUnityProgressChange(0);
7976
if (onUnityReadyStateChange) onUnityReadyStateChange(false);
80-
setLastReadyState(false);
8177

8278
// callbck
8379
if (onComplete) onComplete();
8480
});
81+
82+
setLastReadyState(false);
83+
setCtx(undefined);
84+
85+
// remove the loader script from the DOM
86+
loader.unmount();
8587
}
8688

8789
/**
@@ -92,56 +94,53 @@ export const UnityRenderer: VFC<UnityRendererProps> = ({
9294
* Unity instance.
9395
*/
9496
async function mount(): Promise<void> {
95-
try {
96-
// get the current loader configuration from the UnityContext
97-
const c = ctx.getConfig();
98-
99-
// attach Unity's native JavaScript loader
100-
await loader!.execute(c.loaderUrl);
101-
102-
const instance = await window.createUnityInstance(
103-
renderer!,
104-
{
105-
dataUrl: c.dataUrl,
106-
frameworkUrl: c.frameworkUrl,
107-
codeUrl: c.codeUrl,
108-
streamingAssetsUrl: c.streamingAssetsUrl,
109-
companyName: c.companyName,
110-
productName: c.productName,
111-
productVersion: c.productVersion,
112-
},
113-
(p) => onUnityProgress(p)
97+
if (!ctx || !renderer)
98+
throw new Error(
99+
'cannot mount unity instance without a context or renderer'
114100
);
115101

116-
// set the instance for further JavaScript <--> Unity communication
117-
ctx.setInstance(instance);
118-
} catch (e) {
119-
unmount(() => {
120-
if (onUnityError) onUnityError(e);
121-
});
122-
}
102+
// get the current loader configuration from the UnityContext
103+
const c = ctx.getConfig();
104+
105+
// attach Unity's native JavaScript loader
106+
await loader.execute(c.loaderUrl);
107+
108+
const instance = await window.createUnityInstance(
109+
renderer,
110+
{
111+
dataUrl: c.dataUrl,
112+
frameworkUrl: c.frameworkUrl,
113+
codeUrl: c.codeUrl,
114+
streamingAssetsUrl: c.streamingAssetsUrl,
115+
companyName: c.companyName,
116+
productName: c.productName,
117+
productVersion: c.productVersion,
118+
},
119+
(p) => onUnityProgress(p)
120+
);
121+
122+
// set the instance for further JavaScript <--> Unity communication
123+
ctx.setInstance(instance);
123124
}
124125

125126
// on loader + renderer ready
126127
useEffect(() => {
127-
if (!loader || !renderer) return;
128+
if (!ctx || !renderer) return;
128129

129130
mount().catch((e) => {
130131
if (onUnityError) onUnityError(e);
131-
ctx.shutdown();
132+
ctx?.shutdown();
132133
});
133-
}, [loader, renderer, ctx]);
134+
}, [ctx, renderer]);
134135

135136
// on context change
136137
useEffect(() => {
137-
unmount(() => setCtx(context));
138+
if (context) setCtx(context);
139+
else unmount();
138140
}, [context]);
139141

140142
// on mount
141143
useEffect(() => {
142-
// create the loader service
143-
setLoader(new UnityLoaderService());
144-
145144
// create the renderer and let the ref callback set its handle
146145
setCanvas(
147146
createElement('canvas', {

src/lib/loader.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export class UnityLoaderService {
2-
private documentHead: HTMLHeadElement = document.querySelector('head')!;
2+
private head: HTMLHeadElement = document.querySelector('head')!;
33

44
private script?: HTMLScriptElement;
55

@@ -19,7 +19,10 @@ export class UnityLoaderService {
1919
return resolve();
2020

2121
// another script is currently loaded
22-
if (this.script) this.script.remove();
22+
if (this.script) {
23+
this.script.remove();
24+
this.script = undefined;
25+
}
2326

2427
// create script node
2528
this.script = document.createElement('script');
@@ -31,7 +34,7 @@ export class UnityLoaderService {
3134
reject(new Error(`cannot download unity loader from: ${url}`));
3235

3336
// attach
34-
this.documentHead.appendChild(this.script);
37+
this.head.appendChild(this.script);
3538
});
3639
}
3740

@@ -40,5 +43,6 @@ export class UnityLoaderService {
4043
*/
4144
public unmount(): void {
4245
this.script?.remove();
46+
this.script = undefined;
4347
}
4448
}

0 commit comments

Comments
 (0)