Search code examples
androidunity-game-engineandroid-jetpack-compose

Can I add a Unity scene as a composable?


Currently I have a Unity scene running as a view in an activity (very similar to this solution). As we're migrating to more composables, I'm wondering how to do that in this case. Simplistically I could put a UnityPlayer in an AndroidView composable but I feel like that's missing a lot of context and lifecycle stuff that Unity depends on. I tried a quick proof of concept using an AndroidView composable and didn't get very far. Before spending too long trying to figure it out I thought I'd check if there's a known solution. Has anyone tried this before and found a working solution?

Thank you!


Solution

  • Someone posted an answer yesterday and before I could approve it, it was removed. So here's my version of the answer I was given yesterday. To whoever posted it - thank you.

    @Composable
    fun UnityComposable(modifier: Modifier = Modifier) {
        val context = LocalContext.current
        val unityPlayer = remember { UnityPlayer(context) }
    
        DisposableEffect(Unit) {
            onDispose {
                unityPlayer.quit()
            }
        }
    
        AndroidView(
            modifier = modifier,
            factory = { context ->
                unityPlayer.apply {
                    val params = ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT
                    )
                    layoutParams = params
                }
            },
            update = { view ->
                unityPlayer.settings?.getInt("gles_mode", 1).also {
                    if (it != null) {
                        // Unsure if this is required, but I have it and it works
                        unityPlayer.init(it, false)
                    }
                }
                view.windowFocusChanged(true)
            }
        )
    
        val lifecycleOwner = LocalLifecycleOwner.current
    
        DisposableEffect(lifecycleOwner) {
            val observer = LifecycleEventObserver { _, event ->
                when (event) {
                    Lifecycle.Event.ON_RESUME -> unityPlayer.resume()
                    Lifecycle.Event.ON_PAUSE -> unityPlayer.pause()
                    Lifecycle.Event.ON_DESTROY -> unityPlayer.quit()
                    else -> {}
                }
            }
    
            lifecycleOwner.lifecycle.addObserver(observer)
            onDispose {
                lifecycleOwner.lifecycle.removeObserver(observer)
            }
        }
    }