All Projects → elraccoone → React Unity Webgl

elraccoone / React Unity Webgl

Licence: apache-2.0
React Unity WebGL provides an easy solution for embedding Unity WebGL builds in your React application, with two-way communication between your React and Unity application with advanced API's.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to React Unity Webgl

Anything about game
A wonderful list of Game Development resources.
Stars: ✭ 541 (-9.08%)
Mutual labels:  unity
Jengine
JEngine是针对Unity开发者设计的开箱即用的框架,封装了强大的功能,小白也能快速上手,轻松制作可以热更新的游戏 | JEngine is a streamlined and easy-to-use framework designed for Unity Programmers which contains powerful features, beginners can start up quickly and making hot update-able games easily
Stars: ✭ 564 (-5.21%)
Mutual labels:  unity
Ecs
LeoECS is a fast Entity Component System (ECS) Framework powered by C# with optional integration to Unity
Stars: ✭ 578 (-2.86%)
Mutual labels:  unity
Super Blur
Screen and UI gaussian blur for Unity
Stars: ✭ 543 (-8.74%)
Mutual labels:  unity
Unirx
Reactive Extensions for Unity
Stars: ✭ 5,501 (+824.54%)
Mutual labels:  unity
Mixedreality Webrtc
MixedReality-WebRTC is a collection of components to help mixed reality app developers integrate audio and video real-time communication into their application and improve their collaborative experience
Stars: ✭ 568 (-4.54%)
Mutual labels:  unity
Openupm
OpenUPM - Open Source Unity Package Registry (UPM)
Stars: ✭ 537 (-9.75%)
Mutual labels:  unity
Spritedicing
Unity extension for reusing sprite texture areas
Stars: ✭ 589 (-1.01%)
Mutual labels:  unity
Videolab
Stars: ✭ 563 (-5.38%)
Mutual labels:  unity
Normalpainter
vertex normal editor for Unity
Stars: ✭ 575 (-3.36%)
Mutual labels:  unity
Volsample
Structured Volume Sampling - sample placement algorithm for real-time volume rendering with low aliasing, for camera-in-volume case.
Stars: ✭ 546 (-8.24%)
Mutual labels:  unity
Entitas Csharp
Entitas is a super fast Entity Component System (ECS) Framework specifically made for C# and Unity
Stars: ✭ 5,393 (+806.39%)
Mutual labels:  unity
Render Crowd Of Animated Characters
Animation Baker and Instancing for Animated Characters: Using GPU to implement large-amount animation characters rendering. The animation map for vertex shader to modify the vertex position of the mesh at runtime. Using GPU instancing to reduce draw calls. The initial version was released on GitHub in Jul 2017, and of course, it is still on GitHub. However, if you can buy me a cup of coffee, I will be very happy :-).
Stars: ✭ 571 (-4.03%)
Mutual labels:  unity
Swarm
An example of use of compute shaders and procedural instancing.
Stars: ✭ 547 (-8.07%)
Mutual labels:  unity
Linq To Gameobject For Unity
LINQ to GameObject - Traverse GameObject Hierarchy by LINQ
Stars: ✭ 578 (-2.86%)
Mutual labels:  unity
Rsvfx
An example that shows how to connect RealSense depth camera to Unity VFX Graph
Stars: ✭ 541 (-9.08%)
Mutual labels:  unity
Unitystation
The original unitystation
Stars: ✭ 566 (-4.87%)
Mutual labels:  unity
Unitymeshsimplifier
Mesh simplification for Unity.
Stars: ✭ 592 (-0.5%)
Mutual labels:  unity
Smrvfx
An example that shows how to pass data from a skinned mesh renderer to a visual effect graph.
Stars: ✭ 589 (-1.01%)
Mutual labels:  unity
Unitypack
Python deserialization library for Unity3D Asset format
Stars: ✭ 574 (-3.53%)
Mutual labels:  unity

React Unity WebGL

license npm npm
npm npm npm

When building content for the web, you might need to communicate with elements on a webpage. Or you might want to implement functionality using Web APIs which Unity does not currently expose by default. In both cases, you need to directly interface with the browser’s JavaScript engine. React Unity WebGL provides an easy solution for embedding Unity WebGL builds in your React application, with two-way communication between your React and Unity application with advanced API's.

Documentation · Test Environment · Buy me a Coffee · Discussion Board



npm

Hi! My name is Jeffrey Lanters, thanks for visiting! This package is an open source hobby project with ongoing development. A result of a long road and endless fight with Unity's updates since 2017, full of sleepless nights, working after hours, and busy weekends. If you're using this module for production, please consider donating to support the project. Thank you!

Made with ♥ by Jeffrey Lanters



Installation

Install using npm for your JavaScript or TypeScript React Project. Make sure you download the package version corresponding with your Unity version. I try to update this plugin in case of need as fast as possible. Please keep in mind that some documentation in the readme may not be accurate when using an older version of this module, visit the legacy documentation to see older versions of the Wiki.

$ npm install [email protected]  # For Unity 2020 and 2021
$ npm install [email protected]  # For Unity 2018 and 2019 (LTS)
$ npm install [email protected]  # For Unity 2017 (LTS)
$ npm install [email protected]  # For Unity 5.6^ (LTS)

Documentation

Welcome to the React Unity WebGL Documentation! My name is Jeffrey and I'm here to help you build your awesome games to the web. In the table below you'll find everything there is you'll need to know when using the module. If you'll need help, feel free to open a new discussion, when you want to contribute or think you've found a problem, feel free to open a new issue. Like what you see? Please consider Starring this repository! Happy coding.

Getting Started

It's easy and quick to get your first React Unity project up-and-running. Just make sure you have your Unity WebGL build ready, and have your React project all set up. There are no specific React requirements, any project will do. If it's the first time working with React, I recommend checking out Create React App. Both JavaScript and TypeScript are compatible.

Get started by import the Unity and Unity Context classes from the module. The Unity Context model will house all of your configuration, event listeners and references. Create a new Unity Context Object, pass along the paths to your Unity build and assign it to the Unity component in your Render Method. A basic implementation should look something like this.

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

const App = () => {
  return <Unity unityContext={unityContext} />;
};

Communication from React to Unity

Available since version 5.6.1

Sending messages from React to Unity is done using the Send method available via the Unity Context instance. The Send Method is similar to the SendMessage Method found internally in Unity.

The Method will invoke a public Method on an active GameObject in your Scene. Where gameObjectName is the name of an object in your scene; methodName is the name of a method in the script, currently attached to that object; value can be a string, a number, boolean or not defined at all.

function send(
  gameObjectName: string,
  methodName: string,
  parameter?: string | number | boolean
): void;

Example implementation

A basic implementation could look something like this. In the following example a button is added to the Render. When it's being clicked, a method is invoked telling the Unity Context to send a message to a Game Object named "GameController" to invoke the method "SpawnEnemies" with an Int parameter.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

function spawnEnemies(amount) {
  unityContext.send("GameController", "SpawnEnemies", amount);
}

const App = () => {
  return (
    <div>
      <button onClick={() => spawnEnemies(100)}>Spawn!</button>
      <Unity unityContext={unityContext} />
    </div>
  );
};
// File: EnemyController.cs
// Attached to GameObject "GameController"

public class EnemyController : MonoBehaviour {
  public void SpawnEnemies (int amount) {
    Debug.Log ($"Spawning {amount} enemies!");
  }
}

Communication from Unity to React

Available since version 6.0.0

Sending messages from Unity to React is done using Event Listeners via the Unity Context instance. Invoking these Event Listeners from your Unity Project is quite different.

On the React side of your project an Event Listeners can be registered to the Unity Context instance. Register the Event Listener using the "on" method as following, where "eventName" is the name of your listener, and the "eventListener" method is the Method which will be Invoked which may or may not pass along any Arguments based on your implementation.

Keep in mind communication from Unity to React is global, so Event Listeners with the same name will overwrite one another.

Simple numeric types can be passed to JavaScript in function parameters without requiring any conversion. Other data types will be passed as a pointer in the emscripten heap (which is really just a big array in JavaScript). For strings, you can use the Pointerstringify helper function to convert to a JavaScript string. You can read more about parameters and JavaScript to Unityscript types here.

function on(eventName: string, eventListener: Function): void;

In order to emit Event Listeners, a JSLib file has to be created within your Unity Project "Plugins/WebGL" directory. The React Unity WebGL module exposes a global Object which allows for the emitting of the Event Listeners. When writing your JSLib file, simply invoke the eventName as a member of the "ReactUnityWebGL" object within any method.

ReactUnityWebGL[eventName: string];

Example implementation

A basic implementation could look something like this. In the following example we'll create a new Event Listener with the event name "GameOver" which passes along an interger container the score. When the Event is emitted we'll change the State.

// File: App.jsx

import React, { Component } from "react";
import Unity, { UnityContext } from "react-unity-webgl";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isGameOver: false,
      score: 0,
    };

    this.unityContext = new UnityContext({
      loaderUrl: "build/myunityapp.loader.js",
      dataUrl: "build/myunityapp.data",
      frameworkUrl: "build/myunityapp.framework.js",
      codeUrl: "build/myunityapp.wasm",
    });

    this.unityContext.on("GameOver", (score) => {
      this.setState({
        isGameOver: true,
        score: score,
      });
    });
  }

  render() {
    return (
      <div>
        {this.state.isGameOver == true && (
          <p>Game over! Your score: {this.state.score}</p>
        )}
        <Unity unityContext={this.unityContext} />
      </div>
    );
  }
}

To emit the Event Listener we've just created, we'll have to create a new JSLib file within our Unity Project first. This JSLib file will be places within the "Assets/Plugins/WebGL" directory. The JSLib itself has nothing to do with this module, it is natively supported by Unity.

We'll start of by creating a new method inside of our JSLib. The name of this method can be anything, but in this example we'll give it it the same name as our Event Name to keep things clean. In the body of the method, we'll emit our Event Listener by invoking a method on the "ReactUnityWebGL" object exposed by the module. All of your Event Listeners are available as a property using the Event Name on the object. We'll pass along the score.

// File: MyPlugin.jslib

mergeInto(LibraryManager.library, {
  GameOver: function (score) {
    ReactUnityWebGL.GameOver(score);
  },
});

Finally, to emit to Event Listener within your CSharp code. We're importing the JSLib using Unity's DllImporter as following. When the name of imported Method matches with the Method's name in the JSLib, you can invoke it.

WebGL methods in general are not available in the Unity Editor. Prevent invoking these methods when the Application is not running the WebGL environment, e.g The Unity Editor.

/// File: GameController.cs

using UnityEngine;
using System.Runtime.InteropServices;

public class GameController : MonoBehaviour {

  [DllImport("__Internal")]
  private static extern void GameOver (int score);

  public void SomeMethod () {
    GameOver (100);
  }
}

Tracking the loading progression

Available since version 6.0.1

While your game is being downloaded from the server and loaded into memory, you might want to display some sort of loading indicator informing the user of the progression. The built-in progression event listeners can be used for such cases. On Progress is emitted while the Unity player is being loaded. The parameter contains the progression from 0 to 1. When the game is fully loaded into memory and will start execution, the progression will hit 1. The event will invoke everytime the progression advances.

function on(
  eventName: "progress",
  eventListener: (progression: number) => void
): void;

Example implementation

A basic implementation could look something like this. In the following example we'll track the loading progression and show a loading indicator.

// File: App.jsx

import React, { Component } from "react";
import Unity, { UnityContext } from "react-unity-webgl";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      progression: 0,
    };

    this.unityContext = new UnityContext({
      loaderUrl: "build/myunityapp.loader.js",
      dataUrl: "build/myunityapp.data",
      frameworkUrl: "build/myunityapp.framework.js",
      codeUrl: "build/myunityapp.wasm",
    });

    this.unityContext.on("progress", (progression) => {
      this.setState({
        progression: progression,
      });
    });
  }

  render() {
    return (
      <div>
        <p>Loading... {this.state.progression * 100}%</p>
        <Unity unityContext={this.unityContext} />
      </div>
    );
  }
}

Handeling on when the Application is loaded

Available since version 6.0.2

While your application is being downloaded from the server and loaded into memory, you might want to display some sort of overlay or loading screen. The built-in loaded event listeners can be used for such cases. On Loaded is emitted when the Unity player is loaded into memory and execution is started. Event will be invoked only once.

function on(eventName: "loaded", eventListener: () => void): void;

Example implementation

A basic implementation could look something like this. In the following example we'll set the games visibility to hidden until it's loaded.

// File: App.jsx

import React, { Component } from "react";
import Unity, { UnityContext } from "react-unity-webgl";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoaded: false,
    };

    this.unityContext = new UnityContext({
      loaderUrl: "build/myunityapp.loader.js",
      dataUrl: "build/myunityapp.data",
      frameworkUrl: "build/myunityapp.framework.js",
      codeUrl: "build/myunityapp.wasm",
    });

    this.unityContext.on("loaded", () => {
      this.setState({
        isLoaded: true,
      });
    });
  }

  render() {
    return (
      <div style={{ visibility: this.state.isLoaded ? "visible" : "hidden" }}>
        <Unity unityContext={this.unityContext} />
      </div>
    );
  }
}

Entering or Leaving Fullscreen

Available since version 6.0.6

The Unity context object allows you to enable and disable the fullscreen mode of your application. Cursor locking (using Cursor.lockState) and full-screen mode are both supported in WebGL, implemented using the respective HTML5 APIs (Element.requestPointerLock and Element.requestFullscreen). These are supported in Firefox and Chrome. Safari cannot currently use full-screen and cursor locking. An implementation could look something like:

function setFullscreen(enabled: boolean): void;

Example implementation

A basic implementation could look something like this. In the following example a button is added to the Render. When it's being clicked, the application will enter fullscreen mode.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

function handleOnClickFullscreen() {
  unityContext.setFullscreen(true);
}

const App = () => {
  return (
    <div>
      <button onClick={() => handleOnClickFullscreen()}>Fullscreen</button>
      <Unity unityContext={unityContext} />
    </div>
  );
};

Adding Styles to the Canvas Element

Available since version 8.2.0

The style tag allows for adding inline CSS for styling the component. The style's properties will be assigned directly onto the actual canvas.

The style attribute accepts a JavaScript object with camelCased properties rather than a CSS string. This is consistent with the DOM style JavaScript property, is more efficient, and prevents XSS security holes. React will automatically append a “px” suffix to certain numeric inline style properties. If you want to use units other than “px”, specify the value as a string with the desired unit.

<Unity style={CSSProperties} />

Example implementation

A basic implementation could look something like this. In the following example we'll set the canvas's width to 100%, and the height to a fixed 950px.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

const App = () => {
  return (
    <Unity
      unityContext={unityContext}
      style={{
        height: "100%",
        width: 950,
        border: "2px solid black",
        background: "grey",
      }}
    />
  );
};

Setting the Canvas's ClassName

Available since version 6.0.1

You can add an optional class name to the Unity component. The class name attribute specifies one or more class names for the HTML Canvas Element. The class attribute is mostly used to point to a class in a style sheet. However, it can also be used by a JavaScript (via the HTML DOM) to make changes to HTML elements with a specified class.

<Unity className={string} />

Example implementation

A basic implementation could look something like this. In the following example we'll set the canvas's class name to a spefic value.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

const App = () => {
  return <Unity unityContext={unityContext} className={"game-canvas"} />;
};

Device Pixel Ratio and Retina Support

Available since version 8.1.1 and requires Unity 2020.1 or newer

The Canvas can appear too blurry on retina screens. The device pixel ratio determines how much extra pixel density should be added to allow for a sharper image. The value will be used as a multiplier to the actual canvas scale and will have a big impact on the performance of your application.

<Unity devicePixelRatio={number} />

Example implementation

A basic implementation could look something like this. In the following example we'll set the canvas's device pixel ratio to a value of "2" for sharper images on Retina screens.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

const App = () => {
  return <Unity unityContext={unityContext} devicePixelRatio={2} />;
};

Tab Index and Input Keyboard Capturing

By default, Unity WebGL builds capture the keyboard as soon as it's loaded. This means that all keyboard input on your React Application is captured by the Unity Application instead. Doing so will result in a focus and blur on all keyboard events when clicking on, or around the Unity Application. Implementing the tabIndex of the element mitigates this issue and allows for other elements to be selected.

<Unity tabIndex={number} />

In order for this to work, Capture All Keyboard Input has to be set to false within your Unity Application. Preferably as soon as the Application is loaded. This property determines whether keyboard inputs are captured by WebGL. If this is enabled (default), all inputs will be received by the WebGL canvas regardless of focus, and other elements in the webpage will not receive keyboard inputs. You need to disable this property if you need inputs to be received by other html input elements.

WebGLInput.captureAllKeyboardInput = false;

Example implementation

A basic implementation could look something like this. In the following example we'll set the canvas's tab index to a specific value allowing other elements such as HTML Input Elements and HTML TextArea Elements to capture input too.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

const App = () => {
  return <Unity unityContext={unityContext} tabIndex={1} />;
};
/// File: GameController.cs

using UnityEngine;

public class GameController : MonoBehaviour {
  private void Start () {
#if !UNITY_EDITOR && UNITY_WEBGL
    WebGLInput.captureAllKeyboardInput = false;
#endif
  }
}

Catching Runtime errors

Available since version 7.0.5

When your Applications run into a runtime error, you might want to display your players any kind of error screen, or debug the problem yourself. The built-in error event listeners can be used for such cases. On Error is emitted while the Unity Player runs into an error. This is most likely a runtime error. The error details and stack trace are passed along via the parameter.

Keep in mind that Unity WebGL production builds contain obfuscation code which might be hard to debug.

function on(eventName: "error", eventListener: (message: string) => void): void;

Example implementation

A basic implementation could look something like this. In the following example we'll display the application until an error occurs, then we'll unmount the application and show the error message instead.

// File: App.jsx

import React, { Component } from "react";
import Unity, { UnityContext } from "react-unity-webgl";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      didError: false,
      errorMessage: "",
    };

    this.unityContext = new UnityContext({
      loaderUrl: "build/myunityapp.loader.js",
      dataUrl: "build/myunityapp.data",
      frameworkUrl: "build/myunityapp.framework.js",
      codeUrl: "build/myunityapp.wasm",
    });

    this.unityContext.on("error", (message) => {
      this.setState({
        didError: true,
        errorMessage: message,
      });
    });
  }

  render() {
    return this.state.didError == true ? (
      <div>Oops, that's an error {this.state.errorMessage}</div>
    ) : (
      <Unity unityContext={this.unityConext} />
    );
  }
}

Unmounting, Unloading and Quitting

Available since version 8.0.0 and requires Unity 2020.1 or newer

The quitted event is emitted in two cases, when the Unity component is unmounted, and when Application.Quit is invoked from within your Unity Application. In both cases the Unity Player will be unloaded from memory.

function on(eventName: "quitted", eventListener: () => void): void;

Example implementation

A basic implementation could look something like this. In the following example we'll listen to the event but don't act on it yet.

// File: App.jsx

import React, { Component } from "react";
import Unity, { UnityContext } from "react-unity-webgl";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      didError: false,
      errorMessage: "",
    };

    this.unityContext = new UnityContext({
      loaderUrl: "build/myunityapp.loader.js",
      dataUrl: "build/myunityapp.data",
      frameworkUrl: "build/myunityapp.framework.js",
      codeUrl: "build/myunityapp.wasm",
    });

    this.unityContext.on("quitted", () => {});
  }

  render() {
    return <Unity unityContext={this.unityConext} />;
  }
}

Defining the Streaming Assets URL

Available since version 6.1.0

When using Streaming Assets, a URL (or Path) can be defined where your Unity Application can find these files. The URL will be used as the base of every Streaming Asset request.

<IUnityConfig>{
  streamingAssetsUrl: string,
};

Example implementation

A basic implementation could look something like this. In the following example we'll set the streaming assets url to the "streamingassets" directory.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
  streamingAssetsUrl: "streamingassets",
});

const App = () => {
  return <Unity unityContext={unityContext} />;
};

Overwriting the Unity Modules

Available since version 6.1.1

Overwrites the Unity Modules.

<IUnityConfig>{
  module: Object,
};

Example implementation

A basic implementation could look something like this.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
  module: {},
});

const App = () => {
  return <Unity unityContext={unityContext} />;
};

Providing Application Meta Data

Available since version 8.0.1

Sets the application meta data.

<IUnityConfig>{
  productName: string,
  productVersion: string,
  companyName: string,
};

Example implementation

A basic implementation could look something like this.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
  productName: "My Game",
  productVersion: "1.0.0",
  companyName: "El Raccoone",
});

const App = () => {
  return <Unity unityContext={unityContext} />;
};

Getting a Reference to the Unity Canvas

Available since version 8.2.3

To get a reference to the canvas, we have to wait for the Unity Instance to be loaded, and the Canvas to be appended to the DOM. This is where the Canvas event comes in. The Canvas event is invoked on this exact moment and passes along a reference to the actual Unity Canvas.

function on(
  eventName: "canvas",
  eventListener: (canvas: HTMLCanvasElement) => void
): void;

Example implementation

A basic implementation could look something like this.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

unityContext.on("canvas", (canvas) => {
  canvas.getContext("webgl");
});

const App = () => {
  return <Unity unityContext={unityContext} />;
};

Change the Render Size of WebGL Canvas

Available since version 8.2.3 and requires Unity 2021.1 beta 8 or newer

To customize the WebGL canvas target render size instead of requiring it to always match 1:1 with the High DPI CSS size of the canvas, the match WebGL to canvas size flag can be set to false. Allowing full control over the Canvas Render size using JavaScript.

<Unity matchWebGLToCanvasSize={boolean} />

Example implementation

A basic implementation could look something like this. In this example the canvas will be styled to have a width and height of 100 pixels while setting the actual canvas's renderer size to a width of 100 pixels, and a height of 50 pixels resulting in the image to get stretched.

// File: App.jsx

import React from "react";
import Unity, { UnityContext } from "react-unity-webgl";

const unityContext = new UnityContext({
  loaderUrl: "build/myunityapp.loader.js",
  dataUrl: "build/myunityapp.data",
  frameworkUrl: "build/myunityapp.framework.js",
  codeUrl: "build/myunityapp.wasm",
});

unityContext.on("canvas", (canvas) => {
  canvas.width = 100;
  canvas.height = 50;
});

const App = () => {
  return (
    <Unity
      unityContext={unityContext}
      matchWebGLToCanvasSize={true}
      style={{ width: "100px", height: "100px" }}
    />
  );
};

JavaScript to UnityScript types

Simple numeric types can be passed to JavaScript in function parameters without requiring any conversion. Other data types will be passed as a pointer in the emscripten heap (which is really just a big array in JavaScript). For strings, you can use the Pointerstringify helper function to convert to a JavaScript string.

To return a string value you need to call _malloc to allocate some memory and the writeStringToMemory helper function to write a JavaScript string to it. If the string is a return value, then the il2cpp runtime will take care of freeing the memory for you.

For arrays of primitive types, emscripten provides different ArrayBufferViews into it’s heap for different sizes of integer, unsigned integer or floating point representations of memory: HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64. To access a texture in WebGL, emscripten provides the GL.textures array which maps native texture IDs from Unity to WebGL texture objects. WebGL functions can be called on emscripten’s WebGL context, GLctx.

Example implementation

A basic implementation could look something like this. In this example a series of methods is merged into the Unity library making this methods availble in CSharp. Each of these methods contain an example on how to handle specific types of data. No worries, the methods used for the conversion such as "HEAPF32" and "writeStringToMemory" are available natively.

// File: MyPlugin.jslib

mergeInto(LibraryManager.library, {
  LogToConsole: function () {
    console.log("Hello, world!");
  },
  LogNumberToConsole: function (number) {
    console.log(number);
  },
  LogStringToConsole: function (str) {
    console.log(Pointer_stringify(str));
  },
  LogFloatArrayToConsole: function (array, size) {
    for (var i = 0; i < size; i++) {
      console.log(HEAPF32[(array >> 2) + size]);
    }
  },
  AddNumbers: function (a, b) {
    return a + b;
  },
  ReturnStringValue: function () {
    var returnStr = "bla";
    var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
    writeStringToMemory(returnStr, buffer);
    return buffer;
  },
  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },
});

Contribution and Development

When contributing to this repository, please first discuss the change you wish to make via issue with the owners of this repository before making a change. Before commiting, please compile your code using npm run compile and open a pull request.

Before submitting a pull request, please make sure the following is done:

  • Fork the repository and create your branch from master.
  • Run npm install in the repository root.
  • Ensure the test environment passes using npm start on the library.
  • Format your code with prettier.
  • Make sure your code lints (ts lint).
  • Typecheck all of your changes and make sure JSDocs are provided.
  • If you haven't already, complete the CLA.

Development and test cycle

If you want to modify this package and iteratively test it in inside your application, use the following steps while you're inside the directory of your own application:

Do not use a symlink-based technique (e.g. with the "npm link" command) because npm link breaks libraries that are based on React.

cd ../react-unity-webgl/
npm pack
cd ../your-app
npm remove react-unity-webgl
npm install ../react-unity-webgl/react-unity-webgl-x.y.z.tgz

The "npm pack" command creates a .tgz file exactly the way it would if you were going to publish the package to npm. You can use that .tgz file to install it in your app. That way you can be sure that everything works exactly as it will do when you publish the package, later.

This package here must not have a dependency on React, only a dev dependency on @types/react. Otherwise, the users of this package might install two different versions of React which will lead to problems.

Thanks for your contribution!

Donators

This package is an open source hobby project with ongoing development. A result of a long road and endless fight with Unity's updates since 2017, full of sleepless nights, working after hours, and busy weekends. If you're using this module for production, please consider donating to support the project. Thank you!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].