Integration of Unity WebGL with the tconnect.io SDK
This section of the documentation describes the integration of Unity WebGL applications with the tconnect.io SDK. The goal is to enable communication between a Unity WebGL application and a React application utilizing the tconnect.io SDK.
Overview
Unity is a powerful platform for developing 2D and 3D games and applications, including WebGL applications. Unity WebGL builds can be seamlessly embedded in React applications. Using the tconnect.io SDK, Web3 features such as wallet integration can be added to these applications.
Use Case
We consider a simple WebGL application with two buttons:
Open Modal: A button that opens the React modal, part of the tconnect.io sdk, to connect to a wallet.
Display Address: A button that displays the wallet address connected through the modal in the Unity application.
Implementation Steps
Unity Script: ReactCommunicator
The following Unity script manages communication between the Unity application and React:
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ReactCommunicator : MonoBehaviour
{
// Text field to display received data
public TMP_Text displayText;
// Function called by the button
public void RequestDataFromReact()
{
Debug.Log("Unity: Request sent to React!");
// Calls the JavaScript function in the WebGL build
Application.ExternalCall("sendDataToUnity");
}
public void openModalUnity()
{
Debug.Log("Unity: Open modal");
Application.ExternalCall("openModalUnity");
}
// This function is called by React
public void ReceiveDataFromReact(string data)
{
Debug.Log($"Unity: Data received from React - {data}");
displayText.text = data;
}
}
React Communication Class: useUnityCommunicator
The following React hook manages communication between React and Unity:
import { useTConnectModal } from '@tconnect.io/modal';
import { TConnectTezosBeaconProvider } from '@tconnect.io/tezos-beacon-provider';
import { TConnectTezosWcProvider } from '@tconnect.io/tezos-wc-provider';
import { useCallback, useState } from 'react';
import Web3 from 'web3';
// Import necessary dependencies
// Extend the global `window` object to
// include custom properties for Unity communication
declare global {
interface Window {
// Opens the TConnect modal from Unity
openModalUnity: () => void;
// Sends data to Unity asynchronously
sendDataToUnity: () => Promise<void>;
}
}
// Constants for Unity communication
// Name of the Unity GameObject to send messages to
const UNITY_GAMEOBJECT = 'Canvas';
// Unity method to handle received messages
const UNITY_METHOD = 'ReceiveDataFromReact';
// Custom React hook for Unity communication
export const useUnityCommunicator = (
// Function to send messages to Unity
sendMessage: (gameObject: string, methodName: string, data: string) => void,
) => {
// State to store the user's wallet address
const [address, setAddress] = useState<string | undefined>();
// Get modal functionality and wallet providers from TConnect
const { openModal, etherlinkProvider, tezosBeaconProvider, tezosWcProvider }
= useTConnectModal();
// Function to retrieve the user's Etherlink address
const getAddressEtherlink = useCallback(async () => {
if (!etherlinkProvider) return;
const web3 = new Web3(etherlinkProvider);
const accounts = await web3.eth.getAccounts();
const walletAddress = accounts.length > 0 ? accounts[0] : undefined;
setAddress(walletAddress);
return walletAddress;
}, [etherlinkProvider]);
// Function to retrieve a Tezos wallet address (Beacon or WalletConnect)
const getAddress = useCallback(
async (provider:
TConnectTezosBeaconProvider |
TConnectTezosWcProvider |
undefined) => {
if (!provider) return;
const address = await provider.getPKH();
setAddress(address);
return address;
},
[],
);
// Function to set up communication between React and Unity
const setupUnityCommunication = useCallback(() => {
// Expose the `openModal` functionality to Unity
// via the global `window` object
window.openModalUnity = () => {
openModal(); // Open the TConnect modal
};
// Expose the `sendDataToUnity` functionality to Unity
// via the global `window` object
window.sendDataToUnity = async () => {
// Determine which Tezos provider to use if any
const activeTezosProvider = tezosBeaconProvider || tezosWcProvider;
try {
// Fetch the appropriate address based on the available provider
const data = etherlinkProvider
? // If Etherlink provider is available, get the Ethereum address
await getAddressEtherlink()
: activeTezosProvider
? // Get the Tezos address
await getAddress(activeTezosProvider)
: // Fallback if no provider is available
'not connected';
// If data is available, send it to Unity
if (data) {
// Send the data to Unity
sendMessage(UNITY_GAMEOBJECT, UNITY_METHOD, data);
}
} catch (error) {
// Log any errors that occur during the process
console.error(error || 'React: Error sending data to Unity');
}
};
}, [openModal, getAddressEtherlink, getAddress, sendMessage,
etherlinkProvider, tezosBeaconProvider, tezosWcProvider]);
// Return the `setupUnityCommunication` function and the wallet address state
return {
setupUnityCommunication,
address,
};
};
Embedding Unity in React
Embedding the Unity WebGL Build: The WebGL build can be embedded in React using the react-unity-webglpackage or as iFrame.
Initializing Communication: The useUnityCommunicator hook is used to set up communication between Unity and React.
// Import React's useEffect hook for side effects
import { useEffect } from 'react';
// Import Unity and hooks for integrating Unity with React
import { Unity, useUnityContext } from 'react-unity-webgl';
// Import a custom hook for communication between React and Unity
import { useUnityCommunicator } from './utils/UnityCommunicator';
function App() {
// Extract Unity context details using the useUnityContext hook
const {
unityProvider, // Provides the Unity instance to be rendered
sendMessage, // Sends messages from React to Unity
isLoaded, // Indicates whether the Unity instance has finished loading
loadingProgression, // Tracks the Unity loading progression
} = useUnityContext({
loaderUrl: 'UnityIntegrationBuild/Build/UnityIntegrationBuild.loader.js',
dataUrl: 'UnityIntegrationBuild/Build/UnityIntegrationBuild.data',
frameworkUrl: 'UnityIntegrationBuild/Build/UnityIntegrationBuild.framework.js',
codeUrl: 'UnityIntegrationBuild/Build/UnityIntegrationBuild.wasm',
});
// Use the custom hook to set up Unity
// communication and manage wallet address state
const { setupUnityCommunication, address } = useUnityCommunicator(sendMessage);
// Initialize Unity communication when the component mounts
useEffect(() => {
setupUnityCommunication();
}, [setupUnityCommunication]);
return (
// Render the main application UI
<div className="text-center">
{/* Title of the application */}
<h1 className="text-4xl font-bold mb-4">Unity React Integration</h1>
{/* Display loading progress if Unity is not yet loaded */}
{!isLoaded && <p className="text-lg">loading {Math.floor(loadingProgression * 100)}%</p>}
{/* Render the Unity instance with specific dimensions */}
<div className="mx-auto" style={{ width: 350, height: 600 }}>
<Unity unityProvider={unityProvider}
style={{ width: '100%', height: '100%' }} />
</div>
</div>
);
}
export default App;
Conclusion
By following these steps, Unity WebGL applications can be seamlessly embedded in React and integrated with the tconnect.io SDK. This enables smooth integration of Web3 features such as wallet connectivity into your Unity applications. Our demo application showcases more than just the two functionalities presented; it also supports Get Signature, Transfer, and Show Balance, offering a broader range of Web3 interactions to enhance the user experience. Further customizations can be made based on the specific requirements of your application.